Merges master into hh, fix conflicts

hh
Laurent 6 years ago
commit fca74a3d5e
  1. 2
      app/build.gradle
  2. 10
      app/src/main/java/net/pokeranalytics/android/model/TournamentType.kt
  3. 32
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt
  4. 6
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  5. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/TournamentFeature.kt
  6. 4
      app/src/main/java/net/pokeranalytics/android/model/realm/Transaction.kt
  7. 12
      app/src/main/java/net/pokeranalytics/android/model/realm/TransactionType.kt
  8. 26
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  9. 61
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SettingsFragment.kt
  10. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/CustomFieldDataFragment.kt
  11. 25
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/TransactionDataFragment.kt
  12. 19
      app/src/main/java/net/pokeranalytics/android/ui/graph/GraphExtensions.kt
  13. 11
      app/src/main/java/net/pokeranalytics/android/ui/modules/session/SessionFragment.kt
  14. 9
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/SettingRow.kt
  15. 1
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/TransactionRow.kt
  16. 32
      app/src/main/java/net/pokeranalytics/android/util/FileUtils.kt
  17. 37
      app/src/main/java/net/pokeranalytics/android/util/Preferences.kt
  18. 13
      app/src/main/java/net/pokeranalytics/android/util/TextFormat.kt
  19. 2
      app/src/main/java/net/pokeranalytics/android/util/billing/AppGuard.kt
  20. 60
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVDescriptor.kt
  21. 94
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVField.kt
  22. 3
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  23. 272
      app/src/main/java/net/pokeranalytics/android/util/csv/PACSVDescriptor.kt
  24. 64
      app/src/main/java/net/pokeranalytics/android/util/csv/ProductCSVDescriptors.kt
  25. 376
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionCSVDescriptor.kt
  26. 135
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionField.kt
  27. 118
      app/src/main/java/net/pokeranalytics/android/util/csv/SessionTransactionCSVDescriptor.kt
  28. 78
      app/src/main/java/net/pokeranalytics/android/util/csv/TransactionCSVDescriptor.kt
  29. 5
      app/src/main/java/net/pokeranalytics/android/util/extensions/DateExtension.kt
  30. 28
      app/src/main/res/layout/fragment_subscription.xml
  31. 25
      app/src/main/res/values-de/strings.xml
  32. 24
      app/src/main/res/values-es/strings.xml
  33. 7
      app/src/main/res/values-fr/strings.xml
  34. 24
      app/src/main/res/values-hi/strings.xml
  35. 24
      app/src/main/res/values-it/strings.xml
  36. 24
      app/src/main/res/values-ja/strings.xml
  37. 24
      app/src/main/res/values-pt/strings.xml
  38. 24
      app/src/main/res/values-ru/strings.xml
  39. 24
      app/src/main/res/values-zh/strings.xml
  40. 17
      app/src/main/res/values/strings.xml
  41. 11
      app/src/main/res/xml/provider_paths.xml
  42. 10
      app/src/test/java/net/pokeranalytics/android/BasicUnitTest.kt
  43. 4
      app/standard/release/output.json
  44. 2
      gradle/wrapper/gradle-wrapper.properties

@ -33,7 +33,7 @@ android {
applicationId "net.pokeranalytics.android" applicationId "net.pokeranalytics.android"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 28 targetSdkVersion 28
versionCode 80 versionCode 85
versionName "3.0" versionName "3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }

@ -5,9 +5,9 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class TournamentType : RowRepresentable { enum class TournamentType(val label: String) : RowRepresentable {
MTT, MTT("MTT"),
SNG; SNG("SNG");
companion object { companion object {
val all : List<TournamentType> val all : List<TournamentType>
@ -17,8 +17,8 @@ enum class TournamentType : RowRepresentable {
fun getValueForLabel(label: String) : TournamentType? { fun getValueForLabel(label: String) : TournamentType? {
return when (label) { return when (label) {
"Single-Table" -> SNG SNG.label, "Single-Table" -> SNG
"Multi-Table" -> MTT MTT.label, "Multi-Table" -> MTT
else -> null else -> null
} }
} }

@ -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.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.enumerations.IntIdentifiable import net.pokeranalytics.android.util.enumerations.IntIdentifiable
import timber.log.Timber
import java.util.* import java.util.*
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable { open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable {
companion object {
fun getOrCreate(realm: Realm, name: String, type: Int): CustomField {
val cf = realm.where(CustomField::class.java).equalTo("name", name).findFirst()
return if (cf != null) {
cf
} else {
val customField = CustomField()
customField.name = name
customField.type = type
realm.copyToRealm(customField)
}
}
}
@Ignore @Ignore
override val realmObjectClass: Class<out Identifiable> = CustomField::class.java override val realmObjectClass: Class<out Identifiable> = CustomField::class.java
@ -282,6 +299,19 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
this.entriesToDelete.clear() this.entriesToDelete.clear()
} }
fun getOrCreateEntry(realm: Realm, value: String): CustomFieldEntry {
this.entries.find { it.value == value }?.let {
Timber.d("L>> get")
return it
} ?: run {
Timber.d("L>> create")
val entry = realm.copyToRealm(CustomFieldEntry())
entry.value = value
this.entries.add(entry)
return entry
}
}
/** /**
* Clean the entries if the type is not a list & remove the deleted entries from realm * Clean the entries if the type is not a list & remove the deleted entries from realm
*/ */
@ -308,7 +338,7 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
val criteria: Criteria val criteria: Criteria
get() { get() {
return when (this.type) { return when (this.type) {
CustomField.Type.LIST.uniqueIdentifier -> Criteria.ListCustomFields(this.id) Type.LIST.uniqueIdentifier -> Criteria.ListCustomFields(this.id)
else -> Criteria.ValueCustomFields(this.id) else -> Criteria.ValueCustomFields(this.id)
} }
} }

@ -50,9 +50,9 @@ typealias BB = Double
open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed, open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDataSource, RowRepresentable, Timed,
TimeFilterable, Filterable, DatedBankrollGraphEntry { TimeFilterable, Filterable, DatedBankrollGraphEntry {
enum class Type { enum class Type(val value: String) {
CASH_GAME, CASH_GAME("Cash Game"),
TOURNAMENT; TOURNAMENT("Tournament");
companion object { companion object {

@ -53,7 +53,7 @@ open class TournamentFeature : RealmObject(), NameManageable, StaticRowRepresent
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return TournamentFeature.rowRepresentation return rowRepresentation
} }
override fun charSequenceForRow( override fun charSequenceForRow(

@ -30,13 +30,14 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
companion object { companion object {
fun newInstance(realm: Realm, bankroll: Bankroll, date: Date? = null, type: TransactionType, amount: Double): Transaction { fun newInstance(realm: Realm, bankroll: Bankroll, date: Date? = null, type: TransactionType, amount: Double, comment: String? = null): Transaction {
val transaction = realm.copyToRealm(Transaction()) val transaction = realm.copyToRealm(Transaction())
transaction.date = date ?: Date() transaction.date = date ?: Date()
transaction.amount = amount transaction.amount = amount
transaction.type = type transaction.type = type
transaction.bankroll = bankroll transaction.bankroll = bankroll
transaction.comment = comment ?: ""
return transaction return transaction
} }
@ -174,5 +175,4 @@ open class Transaction : RealmObject(), Manageable, StaticRowRepresentableDataSo
return DefaultLegendValues(this.entryTitle(context), entryValue, totalStatValue, leftName = leftName) return DefaultLegendValues(this.entryTitle(context), entryValue, totalStatValue, leftName = leftName)
} }
} }

@ -68,6 +68,18 @@ open class TransactionType : RealmObject(), NameManageable, StaticRowRepresentab
throw PAIllegalStateException("Transaction type ${value.name} should exist in database!") throw PAIllegalStateException("Transaction type ${value.name} should exist in database!")
} }
fun getOrCreate(realm: Realm, name: String, additive: Boolean): TransactionType {
val type = realm.where(TransactionType::class.java).equalTo("name", name).findFirst()
return if (type != null) {
type
} else {
val transactionType = TransactionType()
transactionType.name = name
transactionType.additive = additive
realm.copyToRealm(transactionType)
}
}
} }
@Ignore @Ignore

@ -4,6 +4,7 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_import.* import kotlinx.android.synthetic.main.fragment_import.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -14,9 +15,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.util.csv.CSVImporter import net.pokeranalytics.android.util.csv.CSVImporter
import net.pokeranalytics.android.util.csv.ImportDelegate import net.pokeranalytics.android.util.csv.ImportDelegate
import net.pokeranalytics.android.util.csv.ImportException
import timber.log.Timber import timber.log.Timber
import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.text.NumberFormat import java.text.NumberFormat
import java.util.* import java.util.*
@ -76,7 +75,7 @@ class ImportFragment : RealmFragment(), ImportDelegate {
this.importer = CSVImporter(inputStream) this.importer = CSVImporter(inputStream)
this.importer.delegate = this this.importer.delegate = this
var error = false var exception: Exception? = null
GlobalScope.launch(coroutineContext) { GlobalScope.launch(coroutineContext) {
@ -86,11 +85,8 @@ class ImportFragment : RealmFragment(), ImportDelegate {
try { try {
importer.start() importer.start()
} catch (e: ImportException) { } catch (e: Exception) {
// shouldDismissActivity = true exception = e
error = true
} catch (e: IOException) {
error = true
} }
val e = Date() val e = Date()
val duration = (e.time - s.time) / 1000.0 val duration = (e.time - s.time) / 1000.0
@ -99,11 +95,17 @@ class ImportFragment : RealmFragment(), ImportDelegate {
} }
test.await() test.await()
if (error && view != null) { val exceptionMessage = exception?.message
Snackbar.make(view!!, R.string.import_error, Snackbar.LENGTH_INDEFINITE).show() if (exceptionMessage != null && view != null) {
val message = exceptionMessage + ". " + requireContext().getString(R.string.import_error)
val snackBar = Snackbar.make(view!!, message, Snackbar.LENGTH_INDEFINITE)
snackBar.setAction(R.string.ok) {
snackBar.dismiss()
}
val textView = snackBar.view.findViewById<TextView>(com.google.android.material.R.id.snackbar_text)
textView.maxLines = 5
snackBar.show()
} }
// if (shouldDismissActivity) { // if (shouldDismissActivity) {
// //

@ -9,6 +9,8 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_settings.* import kotlinx.android.synthetic.main.fragment_settings.*
@ -17,6 +19,7 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.activity.* import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.components.RequestCode import net.pokeranalytics.android.ui.activity.components.RequestCode
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
@ -25,20 +28,25 @@ import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.openContactMail import net.pokeranalytics.android.ui.extensions.openContactMail
import net.pokeranalytics.android.ui.extensions.openPlayStorePage import net.pokeranalytics.android.ui.extensions.openPlayStorePage
import net.pokeranalytics.android.ui.extensions.openUrl import net.pokeranalytics.android.ui.extensions.openUrl
import net.pokeranalytics.android.ui.fragment.components.BaseFragment import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.modules.datalist.DataListActivity import net.pokeranalytics.android.ui.modules.datalist.DataListActivity
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow import net.pokeranalytics.android.ui.view.rowrepresentable.SettingRow
import net.pokeranalytics.android.util.FileUtils
import net.pokeranalytics.android.util.Preferences import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.URL import net.pokeranalytics.android.util.URL
import net.pokeranalytics.android.util.UserDefaults import net.pokeranalytics.android.util.UserDefaults
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts import net.pokeranalytics.android.util.billing.IAPProducts
import net.pokeranalytics.android.util.csv.ProductCSVDescriptors
import net.pokeranalytics.android.util.extensions.dateTimeFileFormatted
import timber.log.Timber import timber.log.Timber
import java.io.File
import java.io.IOException
import java.util.* import java.util.*
class SettingsFragment : BaseFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource { class SettingsFragment : RealmFragment(), RowRepresentableDelegate, StaticRowRepresentableDataSource {
companion object { companion object {
@ -64,6 +72,7 @@ class SettingsFragment : BaseFragment(), RowRepresentableDelegate, StaticRowRepr
private lateinit var settingsAdapterRow: RowRepresentableAdapter private lateinit var settingsAdapterRow: RowRepresentableAdapter
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_settings, container, false) return inflater.inflate(R.layout.fragment_settings, container, false)
} }
@ -134,6 +143,8 @@ class SettingsFragment : BaseFragment(), RowRepresentableDelegate, StaticRowRepr
SettingRow.CONTACT_US -> parentActivity?.openContactMail(R.string.contact) SettingRow.CONTACT_US -> parentActivity?.openContactMail(R.string.contact)
SettingRow.BUG_REPORT -> parentActivity?.openContactMail(R.string.bug_report_subject, Realm.getDefaultInstance().path) SettingRow.BUG_REPORT -> parentActivity?.openContactMail(R.string.bug_report_subject, Realm.getDefaultInstance().path)
SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@SettingsFragment, RequestCode.CURRENCY.value) SettingRow.CURRENCY -> CurrenciesActivity.newInstanceForResult(this@SettingsFragment, RequestCode.CURRENCY.value)
SettingRow.EXPORT_CSV_SESSIONS -> this.sessionsCSVExport()
SettingRow.EXPORT_CSV_TRANSACTIONS -> this.transactionsCSVExport()
SettingRow.FOLLOW_US -> { SettingRow.FOLLOW_US -> {
when (position) { when (position) {
0 -> parentActivity?.openUrl(URL.BLOG.value) 0 -> parentActivity?.openUrl(URL.BLOG.value)
@ -154,6 +165,7 @@ class SettingsFragment : BaseFragment(), RowRepresentableDelegate, StaticRowRepr
} }
} }
/** /**
* Init UI * Init UI
*/ */
@ -205,4 +217,49 @@ class SettingsFragment : BaseFragment(), RowRepresentableDelegate, StaticRowRepr
} }
} }
private fun transactionsCSVExport() {
val transactions = getRealm().where(Transaction::class.java).findAll().sort("date")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroidTransactions.toCSV(transactions)
this.shareCSV(csv, "Transactions")
}
private fun sessionsCSVExport() {
val sessions = getRealm().where(Session::class.java).findAll().sort("startDate")
val csv = ProductCSVDescriptors.pokerAnalyticsAndroid.toCSV(sessions)
this.shareCSV(csv, "Sessions")
}
private fun shareCSV(content: String, dataType: String) {
try {
val fileName = "${dataType.toLowerCase()}_${Date().dateTimeFileFormatted}.csv"
FileUtils.writeFileToFilesDir(content, fileName, requireContext())
this.shareFile(fileName, "Poker Analytics Export", "CSV $dataType")
} catch (e: IOException) {
Toast.makeText(requireContext(), "File write failed: ${e.message}", Toast.LENGTH_LONG).show()
}
}
private fun shareFile(filePath: String, subject: String, body: String) {
val intent = Intent(Intent.ACTION_SEND)
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
val sharedFile = File(requireContext().filesDir, filePath)
val uri = FileProvider.getUriForFile(requireContext(), "net.pokeranalytics.android.fileprovider", sharedFile)
if (sharedFile.exists()) {
intent.type = "application/csv"
intent.putExtra(Intent.EXTRA_STREAM, uri)
intent.putExtra(Intent.EXTRA_SUBJECT, subject)
intent.putExtra(Intent.EXTRA_TEXT, body)
startActivity(Intent.createChooser(intent, "Share File"))
} else {
Timber.d("File located at $filePath does not exists")
}
}
} }

@ -135,7 +135,7 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun boolForRow(row: RowRepresentable): Boolean { override fun boolForRow(row: RowRepresentable): Boolean {
return when (row) { return when (row) {
CustomFieldRow.COPY_ON_DUPLICATE -> customField.duplicateValue CustomFieldRow.COPY_ON_DUPLICATE -> customField.duplicateValue
CustomFieldRow.TYPE -> isUpdating // CustomFieldRow.TYPE -> isUpdating // very weird
else -> super.boolForRow(row) else -> super.boolForRow(row)
} }
} }

@ -1,8 +1,6 @@
package net.pokeranalytics.android.ui.fragment.data package net.pokeranalytics.android.ui.fragment.data
import android.content.Context import android.content.Context
import android.os.Bundle
import android.view.View
import io.realm.kotlin.where import io.realm.kotlin.where
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -22,6 +20,7 @@ import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.round import net.pokeranalytics.android.util.extensions.round
import net.pokeranalytics.android.util.extensions.shortDate import net.pokeranalytics.android.util.extensions.shortDate
import net.pokeranalytics.android.util.extensions.sorted import net.pokeranalytics.android.util.extensions.sorted
import kotlin.math.abs
/** /**
* Custom EditableDataFragment to manage the Transaction data * Custom EditableDataFragment to manage the Transaction data
@ -55,7 +54,7 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
} }
override fun adapterRows(): List<RowRepresentable>? { override fun adapterRows(): List<RowRepresentable>? {
return transaction.adapterRows() return this.transaction.adapterRows()
} }
override fun charSequenceForRow( override fun charSequenceForRow(
@ -66,7 +65,7 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
return when (row) { return when (row) {
TransactionRow.BANKROLL -> this.transaction.bankroll?.name ?: NULL_TEXT TransactionRow.BANKROLL -> this.transaction.bankroll?.name ?: NULL_TEXT
TransactionRow.TYPE -> this.transaction.type?.name ?: NULL_TEXT TransactionRow.TYPE -> this.transaction.type?.name ?: NULL_TEXT
TransactionRow.AMOUNT -> if (this.transaction.amount != 0.0) this.transaction.amount.round() else NULL_TEXT TransactionRow.AMOUNT -> if (this.transaction.amount != 0.0) abs(this.transaction.amount).round() else NULL_TEXT
TransactionRow.COMMENT -> if (this.transaction.comment.isNotEmpty()) this.transaction.comment else NULL_TEXT TransactionRow.COMMENT -> if (this.transaction.comment.isNotEmpty()) this.transaction.comment else NULL_TEXT
TransactionRow.DATE -> this.transaction.date.shortDate() TransactionRow.DATE -> this.transaction.date.shortDate()
else -> super.charSequenceForRow(row, context, 0) else -> super.charSequenceForRow(row, context, 0)
@ -87,7 +86,7 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
"data" to getRealm().sorted<TransactionType>() "data" to getRealm().sorted<TransactionType>()
) )
) )
TransactionRow.AMOUNT -> row.editingDescriptors(mapOf("defaultValue" to (if (this.transaction.amount != 0.0) this.transaction.amount.round() else ""))) TransactionRow.AMOUNT -> row.editingDescriptors(mapOf("defaultValue" to (if (this.transaction.amount != 0.0) abs(this.transaction.amount).round() else "")))
TransactionRow.COMMENT -> row.editingDescriptors(mapOf("defaultValue" to this.transaction.comment)) TransactionRow.COMMENT -> row.editingDescriptors(mapOf("defaultValue" to this.transaction.comment))
else -> super.editDescriptors(row) else -> super.editDescriptors(row)
} }
@ -109,12 +108,19 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row) super.onRowValueChanged(value, row)
rowRepresentableAdapter.refreshRow(row) this.rowRepresentableAdapter.refreshRow(row)
this.selectNextRow(row)
}
/***
* Selects the next row to ease the data capture
*/
private fun selectNextRow(currentRow: RowRepresentable) {
if (model.primaryKey == null) { // automatically change the row for new data if (this.model.primaryKey == null) { // automatically change the row for new data
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
delay(200) delay(200)
when (row) { when (currentRow) {
TransactionRow.BANKROLL -> onRowSelected(0, TransactionRow.TYPE) TransactionRow.BANKROLL -> onRowSelected(0, TransactionRow.TYPE)
TransactionRow.TYPE -> onRowSelected(0, TransactionRow.AMOUNT) TransactionRow.TYPE -> onRowSelected(0, TransactionRow.AMOUNT)
// TransactionRow.AMOUNT -> onRowSelected(0, TransactionRow.DATE) // TransactionRow.AMOUNT -> onRowSelected(0, TransactionRow.DATE)
@ -122,13 +128,14 @@ class TransactionDataFragment : EditableDataFragment(), StaticRowRepresentableDa
} }
} }
} }
} }
override fun willSaveData() { override fun willSaveData() {
super.willSaveData() super.willSaveData()
val additive = this.transaction.type?.additive ?: true val additive = this.transaction.type?.additive ?: true
if (!additive) { if (!additive) {
this.transaction.amount *= -1 this.transaction.amount = abs(this.transaction.amount) * -1
} }
} }

@ -35,7 +35,7 @@ fun BarLineChartBase<*>.setStyle(
this.xAxis.granularity = 1.0f this.xAxis.granularity = 1.0f
this.xAxis.textColor = ContextCompat.getColor(context, R.color.chart_default) this.xAxis.textColor = ContextCompat.getColor(context, R.color.chart_default)
try { try { // can crash for unknown reasons, same below for Y axis
val font = ResourcesCompat.getFont(context, R.font.roboto_medium) val font = ResourcesCompat.getFont(context, R.font.roboto_medium)
this.xAxis.typeface = font this.xAxis.typeface = font
} catch (e: Resources.NotFoundException) { } catch (e: Resources.NotFoundException) {
@ -47,12 +47,8 @@ fun BarLineChartBase<*>.setStyle(
this.xAxis.isEnabled = true this.xAxis.isEnabled = true
when (this) { when (this) {
is BarChart -> { is BarChart -> this.xAxis.setDrawLabels(false)
this.xAxis.setDrawLabels(false) else -> this.xAxis.setDrawLabels(true)
}
else -> {
this.xAxis.setDrawLabels(true)
}
} }
// Y Axis // Y Axis
@ -67,7 +63,14 @@ fun BarLineChartBase<*>.setStyle(
this.axisLeft.granularity = 1.0f this.axisLeft.granularity = 1.0f
this.axisLeft.textColor = ContextCompat.getColor(context, R.color.chart_default) this.axisLeft.textColor = ContextCompat.getColor(context, R.color.chart_default)
this.axisLeft.typeface = ResourcesCompat.getFont(context, R.font.roboto_medium)
try {
val font = ResourcesCompat.getFont(context, R.font.roboto_medium)
this.axisLeft.typeface = font
} catch (e: Resources.NotFoundException) {
Crashlytics.log(e.message)
}
this.axisLeft.labelCount = this.axisLeft.labelCount =
if (small) 1 else 7 // @todo not great if interval is [0..2] for number of records as we get decimals if (small) 1 else 7 // @todo not great if interval is [0..2] for number of records as we get decimals
this.axisLeft.textSize = 12f this.axisLeft.textSize = 12f

@ -236,17 +236,18 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
} }
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
sessionHasBeenUserCustomized = true this.sessionHasBeenUserCustomized = true
try { try {
currentSession.updateValue(value, row) this.currentSession.updateValue(value, row)
} catch (e: PAIllegalStateException) { } catch (e: PAIllegalStateException) {
Toast.makeText(context, e.message, Toast.LENGTH_LONG).show() Toast.makeText(context, e.message, Toast.LENGTH_LONG).show()
return return
} }
sessionAdapter.refreshRow(row) this.sessionAdapter.refreshRow(row)
when (row) { when (row) {
SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT, SessionRow.BUY_IN, SessionRow.TIPS, SessionRow.CASHED_OUT, SessionRow.PRIZE, SessionRow.NET_RESULT,
SessionRow.START_DATE, SessionRow.END_DATE, SessionRow.BANKROLL, SessionRow.BREAK_TIME -> updateSessionUI() SessionRow.BUY_IN, SessionRow.TIPS, SessionRow.START_DATE,
SessionRow.END_DATE, SessionRow.BANKROLL, SessionRow.BREAK_TIME -> updateSessionUI()
} }
} }

@ -29,6 +29,10 @@ enum class SettingRow : RowRepresentable {
LANGUAGE, LANGUAGE,
CURRENCY, CURRENCY,
// Export
EXPORT_CSV_SESSIONS,
EXPORT_CSV_TRANSACTIONS,
// Data management // Data management
CUSTOM_FIELD, CUSTOM_FIELD,
BANKROLL, BANKROLL,
@ -64,6 +68,9 @@ enum class SettingRow : RowRepresentable {
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences)) rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.preferences))
rows.addAll(arrayListOf(CURRENCY)) rows.addAll(arrayListOf(CURRENCY))
rows.add(CustomizableRowRepresentable(customViewType = RowViewType.HEADER_TITLE, resId = R.string.export))
rows.addAll(arrayListOf(EXPORT_CSV_SESSIONS, EXPORT_CSV_TRANSACTIONS))
rows.add( rows.add(
CustomizableRowRepresentable( CustomizableRowRepresentable(
customViewType = RowViewType.HEADER_TITLE, customViewType = RowViewType.HEADER_TITLE,
@ -99,6 +106,8 @@ enum class SettingRow : RowRepresentable {
FOLLOW_US -> R.string.follow_us FOLLOW_US -> R.string.follow_us
LANGUAGE -> R.string.language LANGUAGE -> R.string.language
CURRENCY -> R.string.currency CURRENCY -> R.string.currency
EXPORT_CSV_SESSIONS -> R.string.sessions_csv
EXPORT_CSV_TRANSACTIONS -> R.string.transactions_csv
GDPR -> R.string.gdpr GDPR -> R.string.gdpr
POKER_RUMBLE -> R.string.poker_rumble POKER_RUMBLE -> R.string.poker_rumble
DISCORD -> R.string.join_discord DISCORD -> R.string.join_discord

@ -73,7 +73,6 @@ enum class TransactionRow : RowRepresentable, DefaultEditDataSource {
defaultValue, defaultValue,
inputType = InputType.TYPE_CLASS_NUMBER inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_DECIMAL
or InputType.TYPE_NUMBER_FLAG_SIGNED
)) ))
} }
COMMENT -> { COMMENT -> {

@ -0,0 +1,32 @@
package net.pokeranalytics.android.util
import android.content.Context
import timber.log.Timber
import java.io.BufferedWriter
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStreamWriter
class FileUtils {
companion object{
/***
* Writes a [string] into a file named [fileName], using a [context]
* Should be surrounded by a try/catch IOException
*/
fun writeFileToFilesDir(string: String, fileName: String, context: Context) {
Timber.d("Writing to: $fileName ...\n$string")
val file = File(context.filesDir, fileName)
val fileOutputStream = FileOutputStream(file)
fileOutputStream.write(string.toByteArray())
fileOutputStream.close()
}
}
}

@ -14,22 +14,13 @@ import java.util.*
class Preferences { class Preferences {
interface PreferenceKey { interface PreferenceKey {
var identifier: String val identifier: String
}
enum class DBPatch(var key: String) : PreferenceKey {
LONE_COMPUTABLE_RESULTS("loneComputableResult");
override var identifier: String = ""
get() {
return "dbpatch." + this.key
}
} }
enum class Keys(override var identifier: String) : PreferenceKey { enum class Keys(override var identifier: String) : PreferenceKey {
CURRENCY_CODE("CurrencyCode"), CURRENCY_CODE("CurrencyCode"),
LOCALE_CODE("LocaleCode"), LOCALE_CODE("LocaleCode"),
FIRST_LAUNCH("firstLaunch"), // FIRST_LAUNCH("firstLaunch"),
STOP_SHOWING_DISCLAIMER("stopShowingDisclaimer"), STOP_SHOWING_DISCLAIMER("stopShowingDisclaimer"),
STOP_SHOWING_DUPLICATE("stopShowingDuplicate"), STOP_SHOWING_DUPLICATE("stopShowingDuplicate"),
STOP_SHOWING_DISCORD("stopShowingDiscord"), STOP_SHOWING_DISCORD("stopShowingDiscord"),
@ -99,26 +90,26 @@ class Preferences {
editor.apply() editor.apply()
} }
private fun removeKey(key: Keys, context: Context) { // private fun removeKey(key: Keys, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) // val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit() // val editor = preferences.edit()
editor.remove(key.identifier) // editor.remove(key.identifier)
editor.apply() // editor.apply()
} // }
fun getString(key: Keys, context: Context): String? { fun getString(key: Keys, context: Context): String? {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) val preferences = PreferenceManager.getDefaultSharedPreferences(context)
return preferences.getString(key.identifier, null) return preferences.getString(key.identifier, null)
} }
fun setBoolean(key: PreferenceKey, value: Boolean, context: Context) { private fun setBoolean(key: PreferenceKey, value: Boolean, context: Context) {
val preferences = PreferenceManager.getDefaultSharedPreferences(context) val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val editor = preferences.edit() val editor = preferences.edit()
editor.putBoolean(key.identifier, value) editor.putBoolean(key.identifier, value)
editor.apply() editor.apply()
} }
fun getBoolean( private fun getBoolean(
key: PreferenceKey, key: PreferenceKey,
context: Context, context: Context,
defaultValue: Boolean? = false defaultValue: Boolean? = false
@ -140,15 +131,15 @@ class Preferences {
return getString(Keys.ACTIVE_FILTER_ID, context) return getString(Keys.ACTIVE_FILTER_ID, context)
} }
fun removeActiveFilterId(context: Context) { // fun removeActiveFilterId(context: Context) {
removeKey(Keys.ACTIVE_FILTER_ID, context) // removeKey(Keys.ACTIVE_FILTER_ID, context)
} // }
private fun getCurrencyCode(context: Context): String? { private fun getCurrencyCode(context: Context): String? {
return getString(Keys.CURRENCY_CODE, context) return getString(Keys.CURRENCY_CODE, context)
} }
fun getCurrencyLocale(context: Context): Locale? { private fun getCurrencyLocale(context: Context): Locale? {
getCurrencyCode(context)?.let { currencyCode -> getCurrencyCode(context)?.let { currencyCode ->
UserDefaults.availableCurrencyLocales.filter { UserDefaults.availableCurrencyLocales.filter {
Currency.getInstance(it).currencyCode == currencyCode Currency.getInstance(it).currencyCode == currencyCode

@ -3,6 +3,19 @@ package net.pokeranalytics.android.util
import android.content.Context import android.content.Context
import android.graphics.Color import android.graphics.Color
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
object DotFormatSymbols : DecimalFormatSymbols() {
init {
this.decimalSeparator = '.'
}
}
object CSVNumberFormat : DecimalFormat("#.######", DotFormatSymbols) {
init {
this.isGroupingUsed = false
}
}
class TextFormat(var text: String, var color: Int? = null) { class TextFormat(var text: String, var color: Int? = null) {

@ -64,7 +64,7 @@ object AppGuard : PurchasesUpdatedListener {
if (this.endOfUse != null) return true if (this.endOfUse != null) return true
return if (BuildConfig.DEBUG) { return if (BuildConfig.DEBUG) {
true //false //true false //true
} else { } else {
this._isProUser this._isProUser
} }

@ -16,7 +16,7 @@ enum class DataSource {
POKER_ANALYTICS, POKER_ANALYTICS,
POKER_INCOME, POKER_INCOME,
POKER_BANKROLL_TRACKER, POKER_BANKROLL_TRACKER,
RUNGOOD, RUN_GOOD,
POKER_AGENT POKER_AGENT
} }
@ -28,7 +28,7 @@ abstract class DataCSVDescriptor<T : Identifiable>(source: DataSource, vararg el
/** /**
* List of Realm object identificators * List of Realm object identificators
*/ */
val realmModelIds = mutableListOf<ObjectIdentifier>() private val realmModelIds = mutableListOf<ObjectIdentifier>()
abstract fun parseData(realm: Realm, record: CSVRecord): T? abstract fun parseData(realm: Realm, record: CSVRecord): T?
@ -75,6 +75,35 @@ abstract class DataCSVDescriptor<T : Identifiable>(source: DataSource, vararg el
this.realmModelIds.clear() this.realmModelIds.clear()
} }
open fun prepareCSVExport() {
}
fun toCSV(dataSequence: List<T>): String {
prepareCSVExport()
val lines = mutableListOf<String>()
lines.add(this.csvHeaders)
dataSequence.forEach { data ->
val line = mutableListOf<String>()
this.fields.forEach { field ->
val string = this.toCSV(data, field)
line.add(string ?: "")
}
lines.add(line.joinToString(","))
}
return lines.joinToString("\n")
}
protected open fun toCSV(data: T, field: CSVField): String? {
return null
}
// abstract fun
} }
/** /**
@ -85,7 +114,13 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
/** /**
* The CSVField list describing the CSV header format * The CSVField list describing the CSV header format
*/ */
protected var fields: List<CSVField> = listOf() protected var fields: MutableList<CSVField> = mutableListOf()
/**
* A list of dynamic CSVField, described in the CSV header
*/
// protected var dynamicFields: MutableList<CSVField> = mutableListOf()
/** /**
* The mapping of CSVField with their index in the CSV file * The mapping of CSVField with their index in the CSV file
*/ */
@ -93,7 +128,7 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
init { init {
if (elements.isNotEmpty()) { if (elements.isNotEmpty()) {
this.fields = elements.toList() this.fields = elements.toMutableList()
} }
} }
@ -131,4 +166,21 @@ abstract class CSVDescriptor(var source: DataSource, vararg elements: CSVField)
return count >= mandatoryFields.size return count >= mandatoryFields.size
} }
/***
* Method called when the descriptor has matched a record and has been identified
* as able to parse the file
*/
open fun hasMatched(realm: Realm, record: CSVRecord) {
}
protected val csvHeaders: String
get() {
val headers = mutableListOf<String>()
this.fields.forEach {
headers.add(it.header)
}
return headers.joinToString(",")
}
} }

@ -1,5 +1,8 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.TournamentFeature
import net.pokeranalytics.android.util.CSVNumberFormat
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,8 +15,6 @@ import java.util.*
*/ */
interface NumberCSVField: TypedCSVField<Double> { interface NumberCSVField: TypedCSVField<Double> {
val numberFormat: String?
companion object { companion object {
fun defaultParse(value: String) : Double? { fun defaultParse(value: String) : Double? {
@ -22,10 +23,10 @@ interface NumberCSVField: TypedCSVField<Double> {
return null return null
} }
val formatter = NumberFormat.getInstance(Locale.US) // val formatter = NumberFormat.getInstance(Locale.US)
return try { return try {
formatter.parse(value).toDouble() CSVNumberFormat.parse(value).toDouble()
} catch (e: ParseException) { } catch (e: ParseException) {
Timber.d("Field > Unparseable number: $value") Timber.d("Field > Unparseable number: $value")
null null
@ -43,12 +44,20 @@ interface NumberCSVField: TypedCSVField<Double> {
return it(value) return it(value)
} }
val formatter = NumberFormat.getInstance(Locale.US) // val formatter = NumberFormat.getInstance(Locale.US)
return try { return try {
formatter.parse(value).toDouble() CSVNumberFormat.parse(value).toDouble()
} catch (e: ParseException) { } catch (e: ParseException) {
Timber.d("Field ${header} > Unparseable number: $value") Timber.d("Field $header > Unparseable number: $value")
null
}
}
override fun format(data: Double?): String? {
return if (data != null) {
CSVNumberFormat.format(data)
} else {
null null
} }
} }
@ -63,25 +72,20 @@ interface IntCSVField: TypedCSVField<Int> {
} }
return try { return try {
NumberFormat.getInstance().parse(value).toInt() CSVNumberFormat.parse(value).toInt()
} catch (e: ParseException) { } catch (e: ParseException) {
Timber.d("Field ${header} > Unparseable number: $value") Timber.d("Field $header > Unparseable number: $value")
null null
} }
} }
}
interface DataCSVField<T> : TypedCSVField<T> {
override fun parse(value: String): T? { override fun format(data: Int?): String? {
return if (data != null) {
this.callback?.let { CSVNumberFormat.format(data)
return it(value) } else {
null
} }
return null
} }
} }
interface DateCSVField : TypedCSVField<Date> { interface DateCSVField : TypedCSVField<Date> {
@ -99,6 +103,29 @@ interface DateCSVField : TypedCSVField<Date> {
} }
} }
override fun format(data: Date?): String? {
return if (data != null) {
val formatter = if (dateFormat != null) SimpleDateFormat(dateFormat) else SimpleDateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT)
formatter.format(data)
} else {
null
}
}
}
interface TournamentFeaturesCSVField : TypedCSVField<List<TournamentFeature>> {
override fun parse(value: String): List<TournamentFeature>? {
this.callback?.let {
return it(value)
}
return null
}
override fun format(data: List<TournamentFeature>?): String? {
return data?.joinToString(CSVField.separator) { it.name }
}
} }
interface BlindCSVField : TypedCSVField<Pair<Double, Double>> { interface BlindCSVField : TypedCSVField<Pair<Double, Double>> {
@ -121,23 +148,52 @@ interface BlindCSVField : TypedCSVField<Pair<Double, Double>> {
return null return null
} }
override fun format(data: Pair<Double, Double>?): String? {
data?.let {
val sb = CSVNumberFormat.format(data.first)
val bb = CSVNumberFormat.format(data.second)
return "$sb/$bb"
} ?: run {
return null
}
}
} }
interface BooleanCSVField : TypedCSVField<Boolean> { interface BooleanCSVField : TypedCSVField<Boolean> {
override fun parse(value: String): Boolean? { override fun parse(value: String): Boolean? {
return value == "1" return value == "1"
} }
override fun format(data: Boolean?): String {
return if (data != null && data) "1" else "0"
}
}
interface CustomFieldCSVField : CSVField {
var customField: CustomField
companion object {
val separator: String = "::CF"
}
} }
interface TypedCSVField<T> : CSVField { interface TypedCSVField<T> : CSVField {
fun parse(value: String) : T? fun parse(value: String) : T?
fun format(data: T?): String?
var callback: ((String) -> T?)? var callback: ((String) -> T?)?
} }
interface CSVField { interface CSVField {
companion object {
const val separator = "|"
}
val header: String val header: String
val optional: Boolean val optional: Boolean
get() { get() {
return false return false
} }
} }

@ -112,6 +112,7 @@ open class CSVImporter(istream: InputStream) {
if (this.currentDescriptor == null) { // find descriptor if (this.currentDescriptor == null) { // find descriptor
this.currentDescriptor = this.findDescriptor(record) this.currentDescriptor = this.findDescriptor(record)
this.currentDescriptor?.hasMatched(realm, record)
if (this.currentDescriptor == null) { if (this.currentDescriptor == null) {
@ -120,6 +121,7 @@ open class CSVImporter(istream: InputStream) {
} }
if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) { if (this.descriptorFindingAttempts >= VALID_RECORD_ATTEMPTS_BEFORE_THROWING_EXCEPTION) {
realm.cancelTransaction() realm.cancelTransaction()
realm.close()
throw ImportException("This type of file is not supported") throw ImportException("This type of file is not supported")
} }
} }
@ -150,6 +152,7 @@ open class CSVImporter(istream: InputStream) {
} }
} ?: run { } ?: run {
realm.cancelTransaction() realm.cancelTransaction()
realm.close()
throw ImportException("CSVDescriptor should never be null here") throw ImportException("CSVDescriptor should never be null here")
} }

@ -0,0 +1,272 @@
package net.pokeranalytics.android.util.csv
import net.pokeranalytics.android.model.interfaces.Identifiable
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.Limit
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.model.utils.DataUtils
import net.pokeranalytics.android.util.extensions.getOrCreate
import net.pokeranalytics.android.util.extensions.setHourMinutes
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.util.*
abstract class PACSVDescriptor<T : Identifiable>(source: DataSource,
private var isTournament: Boolean?,
vararg elements: CSVField)
: DataCSVDescriptor<T>(source, *elements) {
private var sameDaySessionCount: Int = 0
private var currentDay: String = ""
private var startInSeconds: Double = 20 * 3600.0
/**
* Parses a [record] and return an optional Session
*/
protected fun parseSession(realm: Realm, record: CSVRecord): Session? {
val isTournament = isTournament ?: false
val session = Session.newInstance(realm, isTournament, managed = false)
var startDate: Date? = null
var endDate: Date? = null
var isLive = true
var bankrollName = ""
var currencyCode: String? = null
var currencyRate: Double? = null
var additionalBuyins = 0.0 // rebuy + addon
var stackingIn: Double? = null
var stackingOut: Double? = null
this.fields.forEach { field ->
this.fieldMapping[field]?.let { index ->
val value = record.get(index)
when (field) {
is SessionField.Start -> {
startDate = field.parse(value)
if (source == DataSource.POKER_AGENT) {
if (currentDay == value) {
sameDaySessionCount++
} else {
sameDaySessionCount = 0
}
currentDay = value
} else {}
}
is SessionField.End -> {
endDate = field.parse(value)
}
is SessionField.StartTime -> {
startDate?.setHourMinutes(value)
}
is SessionField.EndTime -> {
endDate?.setHourMinutes(value)
}
is SessionField.Duration -> {
val hoursDuration = field.parse(value) ?: throw PAIllegalStateException("null duration")
if (startDate != null) {
if (field.randomTime) {
if (sameDaySessionCount == 0) {
startInSeconds = 20 * 3600.0
} else {
startInSeconds -= hoursDuration * 3600.0
}
if (startInSeconds < 0) {
startInSeconds = 20 * 3600.0
// throw PAIllegalStateException("negative start: $startDate, start = $startInSeconds, net = ${session.result?.netResult}")
}
val hour = (startInSeconds / 3600.0).toInt()
val minutes = ((startInSeconds - hour * 3600.0) / 60.0).toInt()
val formattedTime = "$hour:$minutes"
startDate?.setHourMinutes(formattedTime)
}
val seconds = (hoursDuration * 3600.0).toInt()
val calendar = Calendar.getInstance()
calendar.time = startDate
calendar.add(Calendar.SECOND, seconds)
endDate = calendar.time
} else {
throw PAIllegalStateException("start date ($startDate) + hoursDuration ($hoursDuration) required")
}
}
is SessionField.Buyin -> {
val buyin = field.parse(value)
session.result?.buyin = buyin
if (session.type == Session.Type.TOURNAMENT.ordinal) {
session.tournamentEntryFee = buyin
} else {}
}
is SessionField.CashedOut -> session.result?.cashout = field.parse(value)
is SessionField.NetResult -> session.result?.netResult = field.parse(value)
is SessionField.SessionType -> {
Session.Type.getValueFromString(value)?.let { type ->
session.type = type.ordinal
}
}
is SessionField.Live -> isLive = field.parse(value) ?: false
is SessionField.NumberOfTables -> session.numberOfTables = field.parse(value) ?: 1
is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Tips -> session.result?.tips = field.parse(value)
is SessionField.Break -> {
field.parse(value)?.let {
session.breakDuration = it.toLong()
}
}
is SessionField.LimitAndGame -> {
if (value.isNotEmpty()) {
var limitAndGame = value
for (someLimit in Limit.values()) {
if (value.startsWith(someLimit.longName)) {
session.limit = someLimit.ordinal
limitAndGame = limitAndGame.removePrefix(someLimit.longName)
break
}
}
session.game = realm.getOrCreate(limitAndGame.trim())
} else {}
}
is SessionField.Game -> {
if (value.isNotEmpty()) {
session.game = realm.getOrCreate(value)
} else {}
}
is SessionField.Location -> {
val trimmedValue = value.trim()
if (trimmedValue.isNotEmpty()) {
session.location = realm.getOrCreate(trimmedValue)
} else {}
}
is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
is SessionField.Comment -> session.comment = value
is SessionField.Blind -> { // 1/2
val blinds = field.parse(value)
session.cgSmallBlind = blinds?.first
session.cgBigBlind = blinds?.second
}
is SessionField.SmallBlind -> {
val sb = field.parse(value)
if (sb != null && sb > 0.0) {
session.cgSmallBlind = sb
} else {}
}
is SessionField.BigBlind -> {
val bb = field.parse(value)
if (bb != null && bb > 0.0) {
session.cgBigBlind = bb
} else {}
}
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value)
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition =
field.parse(value)
is SessionField.TournamentName -> {
if (value.isNotEmpty()) {
session.tournamentName = realm.getOrCreate(value)
} else {}
}
is SessionField.TournamentTypeName -> session.tournamentType =
TournamentType.getValueForLabel(value)?.ordinal
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers =
field.parse(value)
is SessionField.TournamentEntryFee -> session.tournamentEntryFee = field.parse(value)
is SessionField.TournamentType -> session.tournamentType = field.parse(value)
is SessionField.TournamentFeatures -> {
value.split(CSVField.separator).forEach { featureName ->
val tournamentFeature: TournamentFeature = realm.getOrCreate(featureName)
session.tournamentFeatures.add(tournamentFeature)
}
}
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
is SessionField.StackingIn -> {
stackingIn = field.parse(value)
}
is SessionField.StackingOut -> {
stackingOut = field.parse(value)
}
is SessionField.ListCustomField -> {
val entry = field.customField.getOrCreateEntry(realm, value)
session.customFieldEntries.add(entry)
}
is SessionField.NumberCustomField -> {
val customField = field.customField
field.parse(value)?.let { number ->
Timber.d("N>> create: $number")
val entry = realm.copyToRealm(CustomFieldEntry())
entry.numericValue = number
customField.entries.add(entry)
session.customFieldEntries.add(entry)
} ?: run {
Timber.w("failed parse of numeric value: $value")
}
}
else -> {
}
}
}
}
if (bankrollName.isEmpty()) {
bankrollName = "Import"
}
val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate)
session.bankroll = bankroll
session.result?.buyin?.let {
session.result?.buyin = it + additionalBuyins
}
val net = session.result?.net
if (startDate != null && endDate != null && net != null) { // valid session
// session already in realm, we'd love not put it in Realm before doing the check
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net)
if (count == 0) {
val managedSession = realm.copyToRealm(session)
managedSession.startDate = startDate
managedSession.endDate = endDate
if (stackingIn != null && stackingIn != 0.0) {
val type = TransactionType.getByValue(TransactionType.Value.STACKING_INCOMING, realm)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingIn!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
if (stackingOut != null && stackingOut != 0.0) {
val type = TransactionType.getByValue(TransactionType.Value.STACKING_OUTGOING, realm)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!)
this.addAdditionallyCreatedIdentifiable(transaction)
}
return managedSession
} else {
Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net")
}
} else {
Timber.d("Can't import session: sd=$startDate, ed=$endDate, net=$net")
}
return null
}
}

@ -16,7 +16,9 @@ class ProductCSVDescriptors {
pokerBankrollTracker, pokerBankrollTracker,
runGoodCashGames, runGoodCashGames,
runGoodTournaments, runGoodTournaments,
pokerAnalyticsiOS pokerAnalyticsiOS,
pokerAnalyticsAndroid,
pokerAnalyticsAndroidTransactions
) )
private val pokerAgent: CSVDescriptor private val pokerAgent: CSVDescriptor
@ -57,7 +59,7 @@ class ProductCSVDescriptors {
private val pokerBankrollTracker: CSVDescriptor private val pokerBankrollTracker: CSVDescriptor
get() { get() {
return SessionCSVDescriptor( return SessionTransactionCSVDescriptor(
DataSource.POKER_BANKROLL_TRACKER, DataSource.POKER_BANKROLL_TRACKER,
true, true,
SessionField.Start("starttime", dateFormat = "MM/dd/yy HH:mm"), SessionField.Start("starttime", dateFormat = "MM/dd/yy HH:mm"),
@ -90,7 +92,7 @@ class ProductCSVDescriptors {
private val runGoodTournaments: CSVDescriptor private val runGoodTournaments: CSVDescriptor
get() { get() {
return SessionCSVDescriptor( return SessionCSVDescriptor(
DataSource.RUNGOOD, DataSource.RUN_GOOD,
true, true,
SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"), SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"),
SessionField.StartTime("Start Time"), SessionField.StartTime("Start Time"),
@ -111,7 +113,7 @@ class ProductCSVDescriptors {
SessionField.TournamentName("Event Name"), SessionField.TournamentName("Event Name"),
SessionField.TournamentNumberOfPlayers("Total Players"), SessionField.TournamentNumberOfPlayers("Total Players"),
SessionField.TournamentPosition("Finished Place"), SessionField.TournamentPosition("Finished Place"),
SessionField.TournamentType("Single-Table/Multi-Table") SessionField.TournamentTypeName("Single-Table/Multi-Table")
) )
} }
@ -121,7 +123,7 @@ class ProductCSVDescriptors {
get() { get() {
return SessionCSVDescriptor( return SessionCSVDescriptor(
DataSource.RUNGOOD, DataSource.RUN_GOOD,
false, false,
SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"), SessionField.Start("Start Date", dateFormat = "dd/MM/yyyy"),
SessionField.StartTime("Start Time", dateFormat = "HH:mm"), SessionField.StartTime("Start Time", dateFormat = "HH:mm"),
@ -155,7 +157,7 @@ class ProductCSVDescriptors {
) )
} }
private val pokerAnalyticsiOS: CSVDescriptor val pokerAnalyticsiOS: SessionCSVDescriptor
get() { get() {
return SessionCSVDescriptor( return SessionCSVDescriptor(
DataSource.POKER_ANALYTICS, DataSource.POKER_ANALYTICS,
@ -179,7 +181,7 @@ class ProductCSVDescriptors {
SessionField.CurrencyRate("Currency Rate"), SessionField.CurrencyRate("Currency Rate"),
SessionField.SmallBlind("Small Blind"), SessionField.SmallBlind("Small Blind"),
SessionField.BigBlind("Big Blind"), SessionField.BigBlind("Big Blind"),
SessionField.TournamentType("Tournament Type"), SessionField.TournamentTypeName("Tournament Type"),
SessionField.TournamentEntryFee("Entry fee"), SessionField.TournamentEntryFee("Entry fee"),
SessionField.TournamentNumberOfPlayers("Number of players"), SessionField.TournamentNumberOfPlayers("Number of players"),
SessionField.TournamentPrizePool("Prize Pool"), SessionField.TournamentPrizePool("Prize Pool"),
@ -188,6 +190,54 @@ class ProductCSVDescriptors {
) )
} }
val pokerAnalyticsAndroidTransactions: TransactionCSVDescriptor
get() {
return TransactionCSVDescriptor(
DataSource.POKER_ANALYTICS,
TrField.TransactionDate("Date", dateFormat = "MM/dd/yy HH:mm:ss"),
TrField.Amount("Amount"),
TrField.TransactionType("Type"),
TrField.BankrollName("Bankroll"),
TrField.Live("Live"),
TrField.CurrencyCode("Currency Code"),
TrField.CurrencyRate("Currency Rate"),
TrField.Comment("Comment")
)
}
val pokerAnalyticsAndroid: SessionCSVDescriptor
get() {
return SessionCSVDescriptor(
DataSource.POKER_ANALYTICS,
true,
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"),
SessionField.SessionType("Type"),
SessionField.Live("Live"),
SessionField.NumberOfTables("Tables"),
SessionField.Buyin("Buyin"),
SessionField.CashedOut("Cashed Out"),
SessionField.NetResult("Online Net"),
SessionField.Tips("Tips"),
SessionField.LimitType("Limit"),
SessionField.Game("Game"),
SessionField.TableSize("Table Size"),
SessionField.Location("Location"),
SessionField.Bankroll("Bankroll"),
SessionField.CurrencyCode("Currency Code"),
SessionField.CurrencyRate("Currency Rate"),
SessionField.SmallBlind("Small Blind"),
SessionField.BigBlind("Big Blind"),
SessionField.TournamentTypeName("Tournament Type"),
SessionField.TournamentName("Tournament Name"),
SessionField.TournamentEntryFee("Entry fee"),
SessionField.TournamentNumberOfPlayers("Number of players"),
SessionField.TournamentFeatures("Tournament Features"),
SessionField.TournamentPosition("Position"),
SessionField.Comment("Comment")
)
}
} }
} }

@ -3,349 +3,127 @@ package net.pokeranalytics.android.util.csv
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
import net.pokeranalytics.android.model.TableSize
import net.pokeranalytics.android.model.TournamentType import net.pokeranalytics.android.model.TournamentType
import net.pokeranalytics.android.model.interfaces.Identifiable import net.pokeranalytics.android.model.realm.CustomField
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.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.model.utils.DataUtils
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.*
/** /**
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects * A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects
*/ */
class SessionCSVDescriptor(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) : class SessionCSVDescriptor(source: DataSource, isTournament: Boolean?, vararg elements: CSVField) :
DataCSVDescriptor<Identifiable>(source, *elements) { PACSVDescriptor<Session>(source, isTournament, *elements) {
private enum class DataType { override fun prepareCSVExport() {
TRANSACTION,
SESSION;
companion object {
fun valueForString(type: String): DataType? {
return when (type) {
"Deposit/Payout" -> TRANSACTION
"Cash Game", "Tournament" -> SESSION
else -> null
}
}
}
val realm = Realm.getDefaultInstance()
realm.where(CustomField::class.java).findAll().sort("name").forEach { customField ->
val header = customField.name + CustomFieldCSVField.separator + customField.type
val f = when (customField.type) {
CustomField.Type.LIST.uniqueIdentifier -> {
SessionField.ListCustomField(header, customField)
} }
/**
* Parses a [record] and return an optional Session
*/
override fun parseData(realm: Realm, record: CSVRecord): Identifiable? {
var dataType: DataType? = null
val typeField = fields.firstOrNull { it is SessionField.SessionType }
typeField?.let { field ->
this.fieldMapping[field]?.let { index ->
val typeValue = record.get(index)
dataType = DataType.valueForString(typeValue)
}
}
return when (dataType) {
DataType.TRANSACTION -> parseTransaction(realm, record)
else -> parseSession(realm, record)
}
}
private fun parseTransaction(realm: Realm, record: CSVRecord): Transaction? {
var date: Date? = null
var type: TransactionType? = null
var currencyCode: String? = null
var currencyRate: Double? = null
// Poker Bankroll Tracker specifics
var buyin: Double? = null
var cashedOut: Double? = null
fields.forEach { field ->
val index = this.fieldMapping[field]
if (index != null) {
val value = record.get(index)
when (field) {
is SessionField.Start -> {
date = field.parse(value)
}
is SessionField.Buyin -> buyin = field.parse(value)
is SessionField.CashedOut -> cashedOut = field.parse(value)
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
else -> { else -> {
SessionField.NumberCustomField(header, customField)
} }
} }
this.fields.add(f)
} }
} realm.close()
val amount = if (buyin != null && buyin!! > 0) {
type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm)
buyin!! * -1
} else if (cashedOut != null && cashedOut!! > 0) {
type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm)
cashedOut
} else {
null
}
if (date != null && amount != null && type != null && currencyCode != null) {
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) {
val bankroll = Bankroll.getOrCreate(
realm,
currencyCode!!,
currencyCode = currencyCode!!,
currencyRate = currencyRate
)
return Transaction.newInstance(realm, bankroll, date!!, type, amount)
} else {
Timber.d("Transaction already exists")
}
} else {
Timber.d("Can't import transaction: date=$date, amount=$amount, type=${type?.name}")
} }
return null override fun parseData(realm: Realm, record: CSVRecord): Session? {
return this.parseSession(realm, record)
} }
private var sameDaySessionCount: Int = 0 override fun toCSV(data: Session, field: CSVField): String? {
private var currentday: String = ""
private var startInSeconds: Double = 20 * 3600.0
private fun parseSession(realm: Realm, record: CSVRecord): Session? { return when (field) {
is SessionField.Start -> field.format(data.startDate)
val isTournament = isTournament ?: false is SessionField.End -> field.format(data.endDate)
val session = Session.newInstance(realm, isTournament, managed = false) is SessionField.Break -> field.format(data.breakDuration.toDouble())
is SessionField.SessionType -> Session.Type.values()[data.type].value
var startDate: Date? = null is SessionField.Live -> field.format(data.isLive)
var endDate: Date? = null is SessionField.NumberOfTables -> field.format(data.numberOfTables)
is SessionField.Buyin -> field.format(data.result?.buyin)
var isLive = true is SessionField.CashedOut -> field.format(data.result?.cashout)
var bankrollName = "" is SessionField.NetResult -> field.format(data.result?.netResult)
var currencyCode: String? = null is SessionField.Tips -> field.format(data.result?.tips)
var currencyRate: Double? = null is SessionField.LimitType -> {
var additionalBuyins = 0.0 // rebuy + addon data.limit?.let { limit ->
Limit.values()[limit].longName
var stackingIn: Double? = null
var stackingOut: Double? = null
fields.forEach { field ->
this.fieldMapping[field]?.let { index ->
val value = record.get(index)
when (field) {
is SessionField.Start -> {
startDate = field.parse(value)
if (source == DataSource.POKER_AGENT) {
if (currentday == value) {
sameDaySessionCount++
} else {
sameDaySessionCount = 0
} }
currentday = value
} else {}
} }
is SessionField.End -> { is SessionField.Game -> data.game?.name
endDate = field.parse(value) is SessionField.TableSize -> data.tableSize?.toString()
is SessionField.Location -> data.location?.name
is SessionField.Bankroll -> data.bankroll?.name
is SessionField.CurrencyCode -> data.bankroll?.currency?.code
is SessionField.CurrencyRate -> field.format(data.bankroll?.currency?.rate)
is SessionField.SmallBlind -> field.format(data.cgSmallBlind)
is SessionField.BigBlind -> field.format(data.cgBigBlind)
is SessionField.TournamentType -> field.format(data.tournamentType)
is SessionField.TournamentTypeName -> {
data.tournamentType?.let { tt ->
TournamentType.values()[tt].label
} }
is SessionField.StartTime -> {
startDate?.setHourMinutes(value)
} }
is SessionField.EndTime -> { is SessionField.TournamentName -> data.tournamentName?.name
endDate?.setHourMinutes(value) is SessionField.TournamentFeatures -> field.format(data.tournamentFeatures)
is SessionField.TournamentEntryFee -> field.format(data.tournamentEntryFee)
is SessionField.TournamentNumberOfPlayers -> field.format(data.tournamentNumberOfPlayers)
is SessionField.TournamentPosition -> field.format(data.result?.tournamentFinalPosition)
is SessionField.Comment -> data.comment
is SessionField.NumberCustomField -> {
val entry = data.customFieldEntries.find { it.customField?.id == field.customField.id }
field.format(entry?.numericValue)
} }
is SessionField.Duration -> { is SessionField.ListCustomField -> {
val hoursDuration = field.parse(value) ?: throw PAIllegalStateException("null duration") val entry = data.customFieldEntries.find { it.customField?.id == field.customField.id }
entry?.value
if (startDate != null) {
if (field.randomTime) {
if (sameDaySessionCount == 0) {
startInSeconds = 20 * 3600.0
} else {
startInSeconds -= hoursDuration * 3600.0
} }
else -> null
if (startInSeconds < 0) {
startInSeconds = 20 * 3600.0
// throw PAIllegalStateException("negative start: $startDate, start = $startInSeconds, net = ${session.result?.netResult}")
} }
val hour = (startInSeconds / 3600.0).toInt()
val minutes = ((startInSeconds - hour * 3600.0) / 60.0).toInt()
val formattedTime = "$hour:$minutes"
startDate?.setHourMinutes(formattedTime)
} }
val seconds = (hoursDuration * 3600.0).toInt() override fun hasMatched(realm: Realm, record: CSVRecord) {
val calendar = Calendar.getInstance() super.hasMatched(realm, record)
calendar.time = startDate
calendar.add(Calendar.SECOND, seconds)
endDate = calendar.time
} else {
throw PAIllegalStateException("start date ($startDate) + hoursDuration ($hoursDuration) required")
}
} // identify if the headers has custom fields headers:
is SessionField.Buyin -> { // create the custom fields if not existing
val buyin = field.parse(value) // adds the field to the dynamic list
session.result?.buyin = buyin val headers = record.toSet()
if (session.type == Session.Type.TOURNAMENT.ordinal) { headers.filter { it.contains(CustomFieldCSVField.separator) }.forEach { header ->
session.tournamentEntryFee = buyin
} else {
}
}
is SessionField.CashedOut -> session.result?.cashout = field.parse(value)
is SessionField.NetResult -> session.result?.netResult = field.parse(value)
is SessionField.SessionType -> {
Session.Type.getValueFromString(value)?.let { type ->
session.type = type.ordinal
}
}
is SessionField.Live -> isLive = field.parse(value) ?: false
is SessionField.NumberOfTables -> session.numberOfTables = field.parse(value) ?: 1
is SessionField.Addon -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Rebuy -> additionalBuyins += field.parse(value) ?: 0.0
is SessionField.Tips -> session.result?.tips = field.parse(value)
is SessionField.Break -> {
field.parse(value)?.let {
session.breakDuration = it.toLong()
}
}
is SessionField.LimitAndGame -> {
if (value.isNotEmpty()) {
var limitAndGame = value
for (someLimit in Limit.values()) {
if (value.startsWith(someLimit.longName)) {
session.limit = someLimit.ordinal
limitAndGame = limitAndGame.removePrefix(someLimit.longName)
break
}
}
session.game = realm.getOrCreate(limitAndGame.trim())
} else { val cfProperties = header.split(CustomFieldCSVField.separator)
} if (cfProperties.size != 2) {
} throw PAIllegalStateException("A custom field header is wrongly formed: $header")
is SessionField.Game -> {
if (value.isNotEmpty()) {
session.game = realm.getOrCreate(value)
} else {
}
}
is SessionField.Location -> {
val trimmedValue = value.trim()
if (trimmedValue.isNotEmpty()) {
session.location = realm.getOrCreate(trimmedValue)
} else {
}
}
is SessionField.Bankroll -> bankrollName = value
is SessionField.LimitType -> session.limit = Limit.getInstance(value)?.ordinal
is SessionField.Comment -> session.comment = value
is SessionField.Blind -> { // 1/2
val blinds = field.parse(value)
session.cgSmallBlind = blinds?.first
session.cgBigBlind = blinds?.second
}
is SessionField.SmallBlind -> {
val sb = field.parse(value)
if (sb != null && sb > 0.0) {
session.cgSmallBlind = sb
} else {}
}
is SessionField.BigBlind -> {
val bb = field.parse(value)
if (bb != null && bb > 0.0) {
session.cgBigBlind = bb
} else {}
}
is SessionField.TableSize -> session.tableSize = TableSize.valueForLabel(value)
is SessionField.TournamentPosition -> session.result?.tournamentFinalPosition =
field.parse(value)?.toInt()
is SessionField.TournamentName -> {
if (value.isNotEmpty()) {
session.tournamentName = realm.getOrCreate(value)
} else {
}
}
is SessionField.TournamentType -> session.tournamentType =
TournamentType.getValueForLabel(value)?.ordinal
is SessionField.TournamentNumberOfPlayers -> session.tournamentNumberOfPlayers =
field.parse(value)?.toInt()
is SessionField.TournamentEntryFee -> session.tournamentEntryFee = field.parse(value)
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
is SessionField.StackingIn -> {
stackingIn = field.parse(value)
}
is SessionField.StackingOut -> {
stackingOut = field.parse(value)
}
else -> {
}
}
} }
} val name = cfProperties.first()
val type = cfProperties.last().toInt()
val customField = CustomField.getOrCreate(realm, name, type)
if (bankrollName.isEmpty()) { val field = when (customField.type) {
bankrollName = "Import" CustomField.Type.LIST.uniqueIdentifier -> {
SessionField.ListCustomField(header, customField)
} }
else -> {
val bankroll = Bankroll.getOrCreate(realm, bankrollName, isLive, currencyCode, currencyRate) SessionField.NumberCustomField(header, customField)
session.bankroll = bankroll
session.result?.buyin?.let {
session.result?.buyin = it + additionalBuyins
} }
val net = session.result?.net
if (startDate != null && endDate != null && net != null) { // valid session
// session already in realm, we'd love not put it in Realm before doing the check
val count = DataUtils.sessionCount(realm, startDate!!, endDate!!, net)
if (count == 0) {
val managedSession = realm.copyToRealm(session)
managedSession.startDate = startDate
managedSession.endDate = endDate
if (stackingIn != null && stackingIn != 0.0) {
val type = TransactionType.getByValue(TransactionType.Value.STACKING_INCOMING, realm)
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingIn!!)
this.addAdditionallyCreatedIdentifiable(transaction)
} }
if (stackingOut != null && stackingOut != 0.0) { val index = headers.indexOf(header) // get index in the record
val type = TransactionType.getByValue(TransactionType.Value.STACKING_OUTGOING, realm) if (index >= 0) {
val transaction = Transaction.newInstance(realm, bankroll, startDate, type, stackingOut!!) this.fieldMapping[field] = index
this.addAdditionallyCreatedIdentifiable(transaction)
} }
this.fields.add(field)
return managedSession
} else {
Timber.d("Session already exists(count=$count): sd=$startDate, ed=$endDate, net=$net")
}
} else {
Timber.d("Can't import session: sd=$startDate, ed=$endDate, net=$net")
} }
return null
} }
} }

@ -1,14 +1,39 @@
package net.pokeranalytics.android.util.csv package net.pokeranalytics.android.util.csv
import net.pokeranalytics.android.exceptions.PAIllegalStateException import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.TournamentFeature
import java.util.* import java.util.*
sealed class TransactionField { sealed class TrField {
data class TransactionType( data class TransactionDate(
override var header: String, override var header: String,
override var callback: ((String) -> net.pokeranalytics.android.model.realm.TransactionType?)? = null override var callback: ((String) -> Date?)? = null,
) : DataCSVField<net.pokeranalytics.android.model.realm.TransactionType> override val dateFormat: String? = null
) : DateCSVField
data class Amount(
override var header: String,
override var callback: ((String) -> Double?)? = null
) : NumberCSVField
data class BankrollName(override var header: String) : CSVField
data class Live(
override var header: String,
override var callback: ((String) -> Boolean?)? = null
) : BooleanCSVField
data class CurrencyCode(override var header: String) : CSVField
data class CurrencyRate(
override var header: String,
override var callback: ((String) -> Double?)? = null
) : NumberCSVField
data class TransactionType(override var header: String) : CSVField
data class Comment(override var header: String) : CSVField
} }
@ -44,96 +69,91 @@ sealed class SessionField {
data class Duration( data class Duration(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null,
override val numberFormat: String? = null,
val randomTime: Boolean = false val randomTime: Boolean = false
) : NumberCSVField ) : NumberCSVField
data class Buyin( data class Buyin(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class NetResult( data class NetResult(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class CashedOut( data class CashedOut(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class Break( data class Break(
override var header: String, override var header: String,
var unit: Int = Calendar.MINUTE, var unit: Int = Calendar.MINUTE,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField { ) : NumberCSVField {
override fun parse(value: String): Double? { private val multiplier: Int
get() {
return when (unit) {
Calendar.HOUR -> 3600 * 1000
Calendar.MINUTE -> 60 * 1000
Calendar.SECOND -> 1000
else -> throw PAIllegalStateException("Unmanaged time unit: $unit")
}
}
override fun parse(value: String): Double? {
this.callback?.let { this.callback?.let {
return it(value) return it(value)
} }
val v = NumberCSVField.defaultParse(value) val v = NumberCSVField.defaultParse(value)
val multiplier = when (unit) { return v?.times(this.multiplier)
Calendar.HOUR -> 3600 * 1000
Calendar.MINUTE -> 60 * 1000
Calendar.SECOND -> 1000
else -> throw PAIllegalStateException("Unmanaged time unit: $unit")
} }
return v?.times(multiplier)
override fun format(data: Double?): String? {
return super.format(data?.div(multiplier))
} }
} }
data class Tips( data class Tips(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class SmallBlind( data class SmallBlind(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class BigBlind( data class BigBlind(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class Rebuy( data class Rebuy(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class Addon( data class Addon(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class StackingIn( data class StackingIn(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class StackingOut( data class StackingOut(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class Blind(override var header: String, override var callback: ((String) -> Pair<Double, Double>?)? = null) : data class Blind(override var header: String,
BlindCSVField override var callback: ((String) -> Pair<Double, Double>?)? = null
) : BlindCSVField
data class Live( data class Live(
override var header: String, override var header: String,
@ -156,36 +176,51 @@ sealed class SessionField {
data class TableSize(override var header: String) : CSVField data class TableSize(override var header: String) : CSVField
data class CurrencyCode(override var header: String) : CSVField data class CurrencyCode(override var header: String) : CSVField
data class TournamentName(override var header: String) : CSVField data class TournamentName(override var header: String) : CSVField
data class TournamentType(override var header: String) : CSVField data class TournamentTypeName(override var header: String) : CSVField
data class TournamentFeatures(override var header: String,
override var callback: ((String) -> List<TournamentFeature>?)? = null
) : TournamentFeaturesCSVField
data class CurrencyRate( data class CurrencyRate(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class TournamentPosition( data class TournamentPosition(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Int?)? = null
override val numberFormat: String? = null ) : IntCSVField
) : NumberCSVField
data class TournamentNumberOfPlayers( data class TournamentNumberOfPlayers(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Int?)? = null
override val numberFormat: String? = null ) : IntCSVField
) : NumberCSVField
data class TournamentType(
override var header: String,
override var callback: ((String) -> Int?)? = null
) : IntCSVField
data class TournamentEntryFee( data class TournamentEntryFee(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class TournamentPrizePool( data class TournamentPrizePool(
override var header: String, override var header: String,
override var callback: ((String) -> Double?)? = null, override var callback: ((String) -> Double?)? = null
override val numberFormat: String? = null
) : NumberCSVField ) : NumberCSVField
data class NumberCustomField(
override val header: String,
override var customField: CustomField,
override var callback: ((String) -> Double?)? = null
) : CustomFieldCSVField, NumberCSVField
data class ListCustomField(
override val header: String,
override var customField: CustomField
) : CustomFieldCSVField
} }

@ -0,0 +1,118 @@
package net.pokeranalytics.android.util.csv
import io.realm.Realm
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.model.utils.DataUtils
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.util.*
/**
* A SessionCSVDescriptor is a CSVDescriptor specialized in parsing Session objects
*/
class SessionTransactionCSVDescriptor(source: DataSource, private var isTournament: Boolean?, vararg elements: CSVField) :
PACSVDescriptor<Identifiable>(source, isTournament, *elements) {
private enum class DataType {
TRANSACTION,
SESSION;
companion object {
fun valueForString(type: String): DataType? {
return when (type) {
"Deposit/Payout" -> TRANSACTION
"Cash Game", "Tournament" -> SESSION
else -> null
}
}
}
}
/**
* Parses a [record] and return an optional Session
*/
override fun parseData(realm: Realm, record: CSVRecord): Identifiable? {
var dataType: DataType? = null
val typeField = fields.firstOrNull { it is SessionField.SessionType }
typeField?.let { field ->
this.fieldMapping[field]?.let { index ->
val typeValue = record.get(index)
dataType = DataType.valueForString(typeValue)
}
}
return when (dataType) {
DataType.TRANSACTION -> parseTransaction(realm, record)
else -> parseSession(realm, record)
}
}
private fun parseTransaction(realm: Realm, record: CSVRecord): Transaction? {
var date: Date? = null
var type: TransactionType? = null
var currencyCode: String? = null
var currencyRate: Double? = null
// Poker Bankroll Tracker specifics
var buyin: Double? = null
var cashedOut: Double? = null
this.fields.forEach { field ->
val index = this.fieldMapping[field]
if (index != null) {
val value = record.get(index)
when (field) {
is SessionField.Start -> {
date = field.parse(value)
}
is SessionField.Buyin -> buyin = field.parse(value)
is SessionField.CashedOut -> cashedOut = field.parse(value)
is SessionField.CurrencyCode -> currencyCode = value
is SessionField.CurrencyRate -> currencyRate = field.parse(value)
else -> {
}
}
}
}
val amount = if (buyin != null && buyin!! > 0) {
type = TransactionType.getByValue(TransactionType.Value.WITHDRAWAL, realm)
buyin!! * -1
} else if (cashedOut != null && cashedOut!! > 0) {
type = TransactionType.getByValue(TransactionType.Value.DEPOSIT, realm)
cashedOut
} else {
null
}
if (date != null && amount != null && type != null && currencyCode != null) {
if (DataUtils.transactionUnicityCheck(realm, date!!, amount, type)) {
val bankroll = Bankroll.getOrCreate(
realm,
currencyCode!!,
currencyCode = currencyCode!!,
currencyRate = currencyRate
)
return Transaction.newInstance(realm, bankroll, date!!, type, amount)
} else {
Timber.d("Transaction already exists")
}
} else {
Timber.d("Can't import transaction: date=$date, amount=$amount, type=${type?.name}")
}
return null
}
}

@ -0,0 +1,78 @@
package net.pokeranalytics.android.util.csv
import io.realm.Realm
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.Bankroll
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.model.realm.TransactionType
import net.pokeranalytics.android.model.utils.DataUtils
import org.apache.commons.csv.CSVRecord
import timber.log.Timber
import java.util.*
class TransactionCSVDescriptor(source: DataSource, vararg elements: CSVField) :
DataCSVDescriptor<Transaction>(source, *elements) {
override fun parseData(realm: Realm, record: CSVRecord): Transaction? {
var date: Date? = null
var typeName: String? = null
var bankrollName: String? = null
var amount: Double? = null
var comment: String? = null
var live = false
var currencyCode: String? = null
var currencyRate: Double? = null
for (field in this.fields) {
val index = this.fieldMapping[field]
if (index != null) {
val value = record.get(index)
when (field) {
is TrField.TransactionDate -> date = field.parse(value)
is TrField.TransactionType -> typeName = value
is TrField.Amount -> amount = field.parse(value)
is TrField.BankrollName -> bankrollName = value
is TrField.Live -> live = field.parse(value) ?: true
is TrField.CurrencyCode -> currencyCode = value
is TrField.CurrencyRate -> currencyRate = field.parse(value)
is TrField.Comment -> comment = value
}
}
}
if (date != null && amount != null && typeName != null && bankrollName != null) {
val type = TransactionType.getOrCreate(realm, typeName, amount > 0)
if (DataUtils.transactionUnicityCheck(realm, date, amount, type)) {
val bankroll = Bankroll.getOrCreate(realm, bankrollName, live, currencyCode, currencyRate)
return Transaction.newInstance(realm, bankroll, date, type, amount, comment)
} else {
Timber.d("Transaction already exists")
}
} else {
Timber.d("Can't import transaction: date=$date, amount=$amount, type=$typeName")
}
return null
}
override fun toCSV(data: Transaction, field: CSVField): String? {
return when(field) {
is TrField.TransactionDate -> field.format(data.date)
is TrField.TransactionType -> data.type?.name
is TrField.Amount -> field.format(data.amount)
is TrField.BankrollName -> data.bankroll?.name
is TrField.Live -> field.format(data.bankroll?.live)
is TrField.CurrencyCode -> data.bankroll?.currency?.code
is TrField.CurrencyRate -> field.format(data.bankroll?.currency?.rate)
is TrField.Comment -> data.comment
else -> throw PAIllegalStateException("unmanaged field: $field")
}
}
}

@ -117,6 +117,11 @@ fun Date.getMonthAndYear(): String {
fun Date.getDayMonthYear(): String { fun Date.getDayMonthYear(): String {
return SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()).format(this).capitalize() return SimpleDateFormat("dd MMMM yyyy", Locale.getDefault()).format(this).capitalize()
} }
// Returns a file friendly date time string
val Date.dateTimeFileFormatted: String
get() {
return SimpleDateFormat("yy_MM_dd_hh_mm_ss", Locale.getDefault()).format(this)
}
// Return the netDuration between two dates // Return the netDuration between two dates
fun Date.getFormattedDuration(toDate: Date): String { fun Date.getFormattedDuration(toDate: Date): String {

@ -66,16 +66,15 @@
<androidx.viewpager.widget.ViewPager <androidx.viewpager.widget.ViewPager
android:id="@+id/pager" android:id="@+id/pager"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginBottom="8dp" android:layout_marginBottom="8dp"
app:layout_constraintTop_toBottomOf="@+id/message" app:layout_constraintTop_toBottomOf="@+id/message"
app:layout_constraintBottom_toTopOf="@+id/pageIndicator" app:layout_constraintBottom_toTopOf="@+id/pageIndicator"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.6" app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintVertical_bias="0.4" /> app:layout_constraintVertical_bias="0.5" />
<LinearLayout <LinearLayout
android:id="@+id/pageIndicator" android:id="@+id/pageIndicator"
@ -107,12 +106,31 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:layout_marginBottom="32dp" android:layout_marginBottom="16dp"
android:text="@string/pro_purchase" android:text="@string/pro_purchase"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@id/conditions_scrollview"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintStart_toStartOf="parent" />
<ScrollView
android:id="@+id/conditions_scrollview"
android:layout_width="match_parent"
android:layout_height="120dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<androidx.appcompat.widget.AppCompatTextView
android:text="@string/subscription_text"
android:textColor="@color/gray"
android:paddingBottom="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout> </LinearLayout>

@ -1,11 +1,19 @@
<resources> <resources>
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">Bitte legen Sie ein Startdatum für die Sitzung fest</string> <string name="hour">Stunde</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string> <string name="minute">Minute</string>
<string name="more">More</string> <string name="more">Mehr</string>
<string name="lines">Lines</string> <string name="lines">Linien</string>
<string name="f_unlimited">Unbegrenzt</string>
<string name="f_support">Unterstützung</string>
<string name="imported">Importiert</string>
<string name="save">Sparen</string>
<string name="pending">Steht aus</string>
<string name="from_time">Von</string>
<string name="to_time">Zu</string>
<string name="session_missing_start_date">Bitte legen Sie ein Startdatum für die Sitzung fest</string>
<string name="initial_value">Anfangswert</string> <string name="initial_value">Anfangswert</string>
<string name="less_then_2_values_for_display">Kann nicht gezeigt werden, weil weniger als zwei Werte anzuzeigen sind!</string> <string name="less_then_2_values_for_display">Kann nicht gezeigt werden, weil weniger als zwei Werte anzuzeigen sind!</string>
<string name="invalid_object">Das Objekt, auf das Sie zugreifen wollen, ist ungültig.</string> <string name="invalid_object">Das Objekt, auf das Sie zugreifen wollen, ist ungültig.</string>
@ -14,13 +22,11 @@
<string name="pro_upgrade">Upgrade auf Pro</string> <string name="pro_upgrade">Upgrade auf Pro</string>
<string name="pro_purchase">Pro werden</string> <string name="pro_purchase">Pro werden</string>
<string name="free_trial">Gratisversion</string> <string name="free_trial">Gratisversion</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">Verfolgen Sie Ihr gesamtes Poker-Leben und ergänzen Sie so viele Daten wie gewünscht</string> <string name="f_unlimited_desc">Verfolgen Sie Ihr gesamtes Poker-Leben und ergänzen Sie so viele Daten wie gewünscht</string>
<string name="f_offline">Zuerst offline</string> <string name="f_offline">Zuerst offline</string>
<string name="f_offline_desc">Poker Analytics ist jederzeit verfügbar und die Daten gehören Ihnen. Hinweis: Wir werden bald Exportfunktionen hinzufügen und derzeit sind Sie verantwortlich für Sicherungen. Vielen Dank für Ihre Geduld!</string> <string name="f_offline_desc">Poker Analytics ist jederzeit verfügbar und die Daten gehören Ihnen. Hinweis: Wir werden bald Exportfunktionen hinzufügen und derzeit sind Sie verantwortlich für Sicherungen. Vielen Dank für Ihre Geduld!</string>
<string name="f_privacy">Privat</string> <string name="f_privacy">Privat</string>
<string name="f_privacy_desc">Wir sind nicht Eigentümer von Servern. Wir wissen nichts über Ihre Gewinne und Verluste.</string> <string name="f_privacy_desc">Wir sind nicht Eigentümer von Servern. Wir wissen nichts über Ihre Gewinne und Verluste.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">Wir versuchen so schnell wie möglich zu antworten, auf Englisch oder Französisch!</string> <string name="f_support_desc">Wir versuchen so schnell wie möglich zu antworten, auf Englisch oder Französisch!</string>
<string name="loading_please_wait">Wird geladen, bitte warten…</string> <string name="loading_please_wait">Wird geladen, bitte warten…</string>
<string name="new_report_step_type">Wählen Sie Ihren Berichtstyp</string> <string name="new_report_step_type">Wählen Sie Ihren Berichtstyp</string>
@ -36,7 +42,6 @@
<string name="filter_currently_selected">Der Filter kann nicht gelöscht werden, weil er derzeit ausgewählt ist.</string> <string name="filter_currently_selected">Der Filter kann nicht gelöscht werden, weil er derzeit ausgewählt ist.</string>
<string name="custom_field">Benutzerdefiniertes Feld</string> <string name="custom_field">Benutzerdefiniertes Feld</string>
<string name="transaction_relationship_error">Dieser Posten wird derzeit in einer oder mehreren Transaktionen genutzt…Bitte löschen Sie zuerst die verknüpften Transaktionen.</string> <string name="transaction_relationship_error">Dieser Posten wird derzeit in einer oder mehreren Transaktionen genutzt…Bitte löschen Sie zuerst die verknüpften Transaktionen.</string>
<string name="imported">Imported</string>
<string name="iap_session_message">Sie haben die maximale Anzahl von Gratis-Sitzungen erreicht. Bitte abonnieren Sie für eine unbegrenzte Nutzung und zögern Sie nicht, uns mehr über Ihre derzeitige Nutzererfahrung zu sagen!</string> <string name="iap_session_message">Sie haben die maximale Anzahl von Gratis-Sitzungen erreicht. Bitte abonnieren Sie für eine unbegrenzte Nutzung und zögern Sie nicht, uns mehr über Ihre derzeitige Nutzererfahrung zu sagen!</string>
<string name="stacking_incoming">Eingehender Einsatz</string> <string name="stacking_incoming">Eingehender Einsatz</string>
<string name="stacking_outgoing">Ausgehender Einsatz</string> <string name="stacking_outgoing">Ausgehender Einsatz</string>
@ -47,12 +52,10 @@
<string name="suggestions">Namensvorschläge</string> <string name="suggestions">Namensvorschläge</string>
<string name="data_deleted">Daten gelöscht</string> <string name="data_deleted">Daten gelöscht</string>
<string name="end_date_not_possible">Das Enddatum sollte nach dem Startdatum liegen</string> <string name="end_date_not_possible">Das Enddatum sollte nach dem Startdatum liegen</string>
<string name="save">Save</string>
<string name="tournament_name">Turnierbezeichnung</string> <string name="tournament_name">Turnierbezeichnung</string>
<string name="tournament_names">Turnierbezeichnungen</string> <string name="tournament_names">Turnierbezeichnungen</string>
<string name="tournament_feature">Turniermerkmal</string> <string name="tournament_feature">Turniermerkmal</string>
<string name="tournament_features">Turniermerkmale</string> <string name="tournament_features">Turniermerkmale</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics ist eine Poker-Tracking-App.\nSie können die App über ein Jahresabonnement für unbegrenzte Nutzung erwerben, aber Sie erhalten auch 10 Sitzungen + eine Gratisversion, um die App auszuprobieren.</string> <string name="disclaimer">Poker Analytics ist eine Poker-Tracking-App.\nSie können die App über ein Jahresabonnement für unbegrenzte Nutzung erwerben, aber Sie erhalten auch 10 Sitzungen + eine Gratisversion, um die App auszuprobieren.</string>
<string name="iunderstand">Ich verstehe</string> <string name="iunderstand">Ich verstehe</string>
<string name="tournament_feature_empty_field_error">Sie müssen diesem Turniermerkmal einen Namen geben</string> <string name="tournament_feature_empty_field_error">Sie müssen diesem Turniermerkmal einen Namen geben</string>
@ -61,8 +64,6 @@
<string name="duplicate_tournament_name_error">Diese Bezeichnung existiert bereits.</string> <string name="duplicate_tournament_name_error">Diese Bezeichnung existiert bereits.</string>
<string name="bankroll_relationship_error_transactions">Eine oder mehrere Transaktionen sind mit dieser Finanzierung verknüpft. Bitte löschen Sie zuerst die verknüpften Transaktion(en).</string> <string name="bankroll_relationship_error_transactions">Eine oder mehrere Transaktionen sind mit dieser Finanzierung verknüpft. Bitte löschen Sie zuerst die verknüpften Transaktion(en).</string>
<string name="operation_type">Transaktionstyp</string> <string name="operation_type">Transaktionstyp</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">.</string> <string name="ordinal_suffix_first">.</string>
<string name="ordinal_suffix_second">.</string> <string name="ordinal_suffix_second">.</string>
<string name="ordinal_suffix_third">.</string> <string name="ordinal_suffix_third">.</string>
@ -184,7 +185,7 @@
<string name="conditioning_report_filtering_returns_no_data">Die eingegrenzte Suche ergab keine Ergebnisse</string> <string name="conditioning_report_filtering_returns_no_data">Die eingegrenzte Suche ergab keine Ergebnisse</string>
<string name="confirmation">Bestätigung</string> <string name="confirmation">Bestätigung</string>
<string name="contact">Kontakt</string> <string name="contact">Kontakt</string>
<string name="csv">CSV (Importvorgang fehlgeschlagen)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">One of the lines in your CSV file is not well formed. Please check your file or contact the support.</string> <string name="csv_bad_row_error_message">One of the lines in your CSV file is not well formed. Please check your file or contact the support.</string>
<string name="currency">Währung</string> <string name="currency">Währung</string>
<string name="current_month">Aktueller Monat</string> <string name="current_month">Aktueller Monat</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">Establece una fecha de inicio para la sesión</string> <string name="session_missing_start_date">Establece una fecha de inicio para la sesión</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">Valor inicial</string> <string name="initial_value">Valor inicial</string>
<string name="less_then_2_values_for_display">No se puede mostrar porque hay menos de dos valores para mostrar</string> <string name="less_then_2_values_for_display">No se puede mostrar porque hay menos de dos valores para mostrar</string>
<string name="invalid_object">El objeto al que intentas acceder no es válido</string> <string name="invalid_object">El objeto al que intentas acceder no es válido</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">Actualizar a la versión Pro</string> <string name="pro_upgrade">Actualizar a la versión Pro</string>
<string name="pro_purchase">Avanzar a Pro</string> <string name="pro_purchase">Avanzar a Pro</string>
<string name="free_trial">Prueba gratuita</string> <string name="free_trial">Prueba gratuita</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">Rastrea toda tu vida de póker agregando tantos datos como quieras</string> <string name="f_unlimited_desc">Rastrea toda tu vida de póker agregando tantos datos como quieras</string>
<string name="f_offline">Desconectado primero</string> <string name="f_offline">Desconectado primero</string>
<string name="f_offline_desc">Poker Analytics está disponible en todo momento y los datos son tuyos. Nota: pronto agregaremos capacidad de exportación y por ahora tú estás a cargo de las copias de seguridad. ¡Gracias por tu paciencia!</string> <string name="f_offline_desc">Poker Analytics está disponible en todo momento y los datos son tuyos. Nota: pronto agregaremos capacidad de exportación y por ahora tú estás a cargo de las copias de seguridad. ¡Gracias por tu paciencia!</string>
<string name="f_privacy">Privado</string> <string name="f_privacy">Privado</string>
<string name="f_privacy_desc">No poseemos servidores. No sabemos nada sobre tus victorias y derrotas.</string> <string name="f_privacy_desc">No poseemos servidores. No sabemos nada sobre tus victorias y derrotas.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">Intentamos responder lo más rápido posible en inglés o francés.</string> <string name="f_support_desc">Intentamos responder lo más rápido posible en inglés o francés.</string>
<string name="loading_please_wait">Cargando, espera…</string> <string name="loading_please_wait">Cargando, espera…</string>
<string name="new_report_step_type">Selecciona tu tipo de reporte</string> <string name="new_report_step_type">Selecciona tu tipo de reporte</string>
@ -37,7 +31,6 @@
<string name="custom_field">Campo personalizado</string> <string name="custom_field">Campo personalizado</string>
<string name="transaction_relationship_error">El artículo se utiliza en una o más transacciones.… <string name="transaction_relationship_error">El artículo se utiliza en una o más transacciones.…
Primero elimina las transacciones vinculadas</string> Primero elimina las transacciones vinculadas</string>
<string name="imported">Imported</string>
<string name="iap_session_message">Has alcanzado el número máximo de sesiones gratuitas. ¡Suscríbete para un uso ilimitado y no olvides contarnos tu propia experiencia!</string> <string name="iap_session_message">Has alcanzado el número máximo de sesiones gratuitas. ¡Suscríbete para un uso ilimitado y no olvides contarnos tu propia experiencia!</string>
<string name="stacking_incoming">Apuesta entrante</string> <string name="stacking_incoming">Apuesta entrante</string>
<string name="stacking_outgoing">Apuesta saliente</string> <string name="stacking_outgoing">Apuesta saliente</string>
@ -50,12 +43,10 @@ Una suscripción se renueva automáticamente a menos que se cancele\n• Puedes
<string name="suggestions">Sugerencias de nombres</string> <string name="suggestions">Sugerencias de nombres</string>
<string name="data_deleted">Datos borrados</string> <string name="data_deleted">Datos borrados</string>
<string name="end_date_not_possible">La fecha de finalización debe ser posterior a la fecha de inicio</string> <string name="end_date_not_possible">La fecha de finalización debe ser posterior a la fecha de inicio</string>
<string name="save">Save</string>
<string name="tournament_name">Nombre del torneo</string> <string name="tournament_name">Nombre del torneo</string>
<string name="tournament_names">Nombres de torneos</string> <string name="tournament_names">Nombres de torneos</string>
<string name="tournament_feature">Función del torneo</string> <string name="tournament_feature">Función del torneo</string>
<string name="tournament_features">Funciones de torneos</string> <string name="tournament_features">Funciones de torneos</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics es una aplicación de seguimiento de póker.\n <string name="disclaimer">Poker Analytics es una aplicación de seguimiento de póker.\n
La aplicación funciona con una suscripción anual para uso ilimitado, pero obtienes 10 sesiones, además de una prueba gratuita para probar la aplicación.</string> La aplicación funciona con una suscripción anual para uso ilimitado, pero obtienes 10 sesiones, además de una prueba gratuita para probar la aplicación.</string>
<string name="iunderstand">Comprendo</string> <string name="iunderstand">Comprendo</string>
@ -65,8 +56,6 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="duplicate_tournament_name_error">Ya existe este nombre</string> <string name="duplicate_tournament_name_error">Ya existe este nombre</string>
<string name="bankroll_relationship_error_transactions">Una o más transacciones están asociadas con este fondo, elimina primero la o las transacciones vinculadas.</string> <string name="bankroll_relationship_error_transactions">Una o más transacciones están asociadas con este fondo, elimina primero la o las transacciones vinculadas.</string>
<string name="operation_type">Tipo de transacción</string> <string name="operation_type">Tipo de transacción</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first"> </string> <string name="ordinal_suffix_first"> </string>
<string name="ordinal_suffix_second"> </string> <string name="ordinal_suffix_second"> </string>
<string name="ordinal_suffix_third"> </string> <string name="ordinal_suffix_third"> </string>
@ -88,6 +77,17 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour">Hora</string>
<string name="minute">Minuto</string>
<string name="more">Más</string>
<string name="lines">Líneas</string>
<string name="f_unlimited">Ilimitado</string>
<string name="f_support">Apoyo</string>
<string name="imported">Importado</string>
<string name="save">Salvar</string>
<string name="pending">Pendiente</string>
<string name="from_time">Desde</string>
<string name="to_time">A</string>
<string name="_ago">hace %s </string> <string name="_ago">hace %s </string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s no tiene acceso a tus contactos y no puede encontrar el nombre de tus amigos existentes. Puedes otorgar acceso a través de las preferencias del iPhone para evitar nombres de \'usuario desconocido\'.</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s no tiene acceso a tus contactos y no puede encontrar el nombre de tus amigos existentes. Puedes otorgar acceso a través de las preferencias del iPhone para evitar nombres de \'usuario desconocido\'.</string>
@ -188,7 +188,7 @@ La aplicación funciona con una suscripción anual para uso ilimitado, pero obti
<string name="conditioning_report_filtering_returns_no_data">Los filtros aún no dieron ningún resultado.</string> <string name="conditioning_report_filtering_returns_no_data">Los filtros aún no dieron ningún resultado.</string>
<string name="confirmation">Confirmación</string> <string name="confirmation">Confirmación</string>
<string name="contact">Contáctanos</string> <string name="contact">Contáctanos</string>
<string name="csv">CSV (no se puede importar)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">Una de las líneas en tu archivo CSV no está bien formada. Verifica el archivo o contacta al soporte.</string> <string name="csv_bad_row_error_message">Una de las líneas en tu archivo CSV no está bien formada. Verifica el archivo o contacta al soporte.</string>
<string name="currency">Divisa</string> <string name="currency">Divisa</string>
<string name="current_month">Mes en curso</string> <string name="current_month">Mes en curso</string>

@ -10,7 +10,6 @@
<string name="hour">Heure</string> <string name="hour">Heure</string>
<string name="minute">Minute</string> <string name="minute">Minute</string>
<string name="more">Autre</string> <string name="more">Autre</string>
<string name="variant">Jeu</string>
<string name="lines">Lignes</string> <string name="lines">Lignes</string>
<string name="initial_value">Valeur initiale</string> <string name="initial_value">Valeur initiale</string>
<string name="less_then_2_values_for_display">Il faut au moins deux valeurs pour afficher ce rapport!</string> <string name="less_then_2_values_for_display">Il faut au moins deux valeurs pour afficher ce rapport!</string>
@ -56,7 +55,7 @@
<string name="update_entity" formatted="false">Mise-à-jour %s</string> <string name="update_entity" formatted="false">Mise-à-jour %s</string>
<!-- Not translated --> <!-- Not translated -->
<string name="address">Adresse</string> <!-- <string name="address">Adresse</string>-->
<string name="suggestions">Suggestions de noms</string> <string name="suggestions">Suggestions de noms</string>
<string name="data_deleted">Élément effacé</string> <string name="data_deleted">Élément effacé</string>
<string name="end_date_not_possible">La date de fin doit être après la date de début</string> <string name="end_date_not_possible">La date de fin doit être après la date de début</string>
@ -173,7 +172,7 @@
<string name="conditioning_report_filtering_returns_no_data">Le filtre ne retourne aucun résultat</string> <string name="conditioning_report_filtering_returns_no_data">Le filtre ne retourne aucun résultat</string>
<string name="confirmation">Confirmation</string> <string name="confirmation">Confirmation</string>
<string name="contact">Contactez-nous</string> <string name="contact">Contactez-nous</string>
<string name="csv">CSV (ne peut être importé)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">Une ligne de votre fichier CSV est mal formée. Veuillez vérifier votre fichier ou contacter le support.</string> <string name="csv_bad_row_error_message">Une ligne de votre fichier CSV est mal formée. Veuillez vérifier votre fichier ou contacter le support.</string>
<string name="currency">Devise</string> <string name="currency">Devise</string>
<string name="current_month">Ce mois-ci</string> <string name="current_month">Ce mois-ci</string>
@ -670,7 +669,7 @@
<string name="intermediate_sub_short_title">Semi-Pro</string> <string name="intermediate_sub_short_title">Semi-Pro</string>
<string name="pro_sub_short_title">Pro</string> <string name="pro_sub_short_title">Pro</string>
<string name="subscription_details">Conditions de l\'abonnement</string> <string name="subscription_details">Conditions de l\'abonnement</string>
<string name="subscription_text">Conditions d’utilisations concernant l’abonnement:\n- Le paiement sera facturé sur votre compte iTunes.\n- L’abonnement est renouvelé automatiquement chaque année, à moins d’avoir été désactivé au moins 24 heures avant la fin de la période de l’abonnement.\n- L’abonnement peut être géré par l’utilisateur et désactivé en allant dans les réglages de son compte après s’être abonné.\n- Le compte sera facturé pour le renouvellement de l\'abonnement dans les 24 heures précédent la fin de la période d’abonnement.\n- Un abonnement en cours ne peut être annulé.\n- Toute partie inutilisée de l\'offre gratuite, si souscrite, sera abandonnée lorsque l\'utilisateur s\'abonnera, dans les cas applicables</string> <string name="subscription_text">Conditions d’utilisations:\n• Votre compte ne sera pas prélevé pendant toute la durée de l\'essai gratuit\n• A la fin de l\'essai gratuit, vous serez automatiquement prélevé du montant total de l\'abonnement annuel\n• Un abonnement est automatiquement renouvelé sauf si annulé\n• Votre abonnement peut-être géré en allant dans le tab \"Autre\" de l\'app, puis \"Abonnement\"</string>
<string name="privacy_policy">Politique de confidentialité</string> <string name="privacy_policy">Politique de confidentialité</string>
<string name="bug_report_message">Nous sommes désolé, mais il y a problème&#8230;Il est possible qu\'iCloud synchronise vos données. Veuillez réessayer plus tard. Pouvez-vous nous envoyer un rapport expliquant l\'état de l\'app pour nous aider à résoudre le problème? Merci!</string> <string name="bug_report_message">Nous sommes désolé, mais il y a problème&#8230;Il est possible qu\'iCloud synchronise vos données. Veuillez réessayer plus tard. Pouvez-vous nous envoyer un rapport expliquant l\'état de l\'app pour nous aider à résoudre le problème? Merci!</string>
<string name="longtap_to_duplicate">Appuyez et maintenez sur une session pour la dupliquer</string> <string name="longtap_to_duplicate">Appuyez et maintenez sur une session pour la dupliquer</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">पय सतर किए एक आरभ तख सट कर</string> <string name="session_missing_start_date">पय सतर किए एक आरभ तख सट कर</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">आरिक म</string> <string name="initial_value">आरिक म</string>
<string name="less_then_2_values_for_display">रदरित नह कर सकतििसपन द कम ह!</string> <string name="less_then_2_values_for_display">रदरित नह कर सकतििसपन द कम ह!</string>
<string name="invalid_object">उदय जिसक आप परयस कर रह वह अमय ह</string> <string name="invalid_object">उदय जिसक आप परयस कर रह वह अमय ह</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade"> अपगड कर</string> <string name="pro_upgrade"> अपगड कर</string>
<string name="pro_purchase"></string> <string name="pro_purchase"></string>
<string name="free_trial">त टयल</string> <string name="free_trial">त टयल</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">आप जितन उतनकर आपक समसत पकर जवन कक कर</string> <string name="f_unlimited_desc">आप जितन उतनकर आपक समसत पकर जवन कक कर</string>
<string name="f_offline">ऑफलइन पहल</string> <string name="f_offline">ऑफलइन पहल</string>
<string name="f_offline_desc">Poker Analytics हर समय उपलबध ह और ड आपक. नट: हम जलद ह एकसपिग कषमत और वरतमन म आप बकअप कज ह. आपकय किए धनयवद!</string> <string name="f_offline_desc">Poker Analytics हर समय उपलबध ह और ड आपक. नट: हम जलद ह एकसपिग कषमत और वरतमन म आप बकअप कज ह. आपकय किए धनयवद!</string>
<string name="f_privacy">ि</string> <string name="f_privacy">ि</string>
<string name="f_privacy_desc">हमस सरवर नह. हम आपकत और हछ भ नहनत.</string> <string name="f_privacy_desc">हमस सरवर नह. हम आपकत और हछ भ नहनत.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">हम जितन जलभव ह, इिश यच म जवब दरयस करत!</string> <string name="f_support_desc">हम जितन जलभव ह, इिश यच म जवब दरयस करत!</string>
<string name="loading_please_wait">ड ह रह, कपयरत कर</string> <string name="loading_please_wait">ड ह रह, कपयरत कर</string>
<string name="new_report_step_type">आपकिट करकर च</string> <string name="new_report_step_type">आपकिट करकर च</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">िटर हट नह सकति वरतमन म इसआ ह.</string> <string name="filter_currently_selected">िटर हट नह सकति वरतमन म इसआ ह.</string>
<string name="custom_field">कसटम फ</string> <string name="custom_field">कसटम फ</string>
<string name="transaction_relationship_error">यह आयटम एक य अधिक लनदन म उपयग क गई ह…कपय पहलिक हए लनदन हट</string> <string name="transaction_relationship_error">यह आयटम एक य अधिक लनदन म उपयग क गई ह…कपय पहलिक हए लनदन हट</string>
<string name="imported">Imported</string>
<string name="iap_session_message">आप मत सत अधिकतम स तक पहच गए ह. असित उपयग किए कपय सदसयत और हमिच बति आपक अपन वरतमन अनभव कथ क महसस ह!</string> <string name="iap_session_message">आप मत सत अधिकतम स तक पहच गए ह. असित उपयग किए कपय सदसयत और हमिच बति आपक अपन वरतमन अनभव कथ क महसस ह!</string>
<string name="stacking_incoming">व इनकमि</string> <string name="stacking_incoming">व इनकमि</string>
<string name="stacking_outgoing">व आउटग</string> <string name="stacking_outgoing">व आउटग</string>
@ -47,12 +40,10 @@
<string name="suggestions">मकरण स</string> <string name="suggestions">मकरण स</string>
<string name="data_deleted"> हट गय</string> <string name="data_deleted"> हट गय</string>
<string name="end_date_not_possible">समिख आरभ तख कद हि</string> <string name="end_date_not_possible">समिख आरभ तख कद हि</string>
<string name="save">Save</string>
<string name="tournament_name">ट क</string> <string name="tournament_name">ट क</string>
<string name="tournament_names">ट क</string> <string name="tournament_names">ट क</string>
<string name="tournament_feature">ट किषत</string> <string name="tournament_feature">ट किषत</string>
<string name="tournament_features">ट किषत</string> <string name="tournament_features">ट किषत</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics एक पकर टिग एपप ह.\nएपप विक सदसयतथ एक असित उपयग कप मय करत, लिन आपक एपप क परषण करनिए 10 सतर + एक मत टयल मिलत.</string> <string name="disclaimer">Poker Analytics एक पकर टिग एपप ह.\nएपप विक सदसयतथ एक असित उपयग कप मय करत, लिन आपक एपप क परषण करनिए 10 सतर + एक मत टयल मिलत.</string>
<string name="iunderstand"> समझ गय/गई</string> <string name="iunderstand"> समझ गय/गई</string>
<string name="tournament_feature_empty_field_error">आपक इस टट विषतिए एक नम द जररत ह</string> <string name="tournament_feature_empty_field_error">आपक इस टट विषतिए एक नम द जररत ह</string>
@ -61,8 +52,6 @@
<string name="duplicate_tournament_name_error">यह नम पहलद ह.</string> <string name="duplicate_tournament_name_error">यह नम पहलद ह.</string>
<string name="bankroll_relationship_error_transactions">इस बकरल कथ एक य अधिक लनदन ज, कपय पहलिक हए लनदन (न) क हट.</string> <string name="bankroll_relationship_error_transactions">इस बकरल कथ एक य अधिक लनदन ज, कपय पहलिक हए लनदन (न) क हट.</string>
<string name="operation_type">नदन करक</string> <string name="operation_type">नदन करक</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">st</string> <string name="ordinal_suffix_first">st</string>
<string name="ordinal_suffix_second">nd</string> <string name="ordinal_suffix_second">nd</string>
<string name="ordinal_suffix_third">rd</string> <string name="ordinal_suffix_third">rd</string>
@ -84,6 +73,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour"></string>
<string name="minute">िनट</string>
<string name="more">अधि</string>
<string name="lines">ि</string>
<string name="f_unlimited">असि</string>
<string name="f_support">सहय</string>
<string name="imported">आयि</string>
<string name="save">सह</string>
<string name="pending">ि</string>
<string name="from_time"></string>
<string name="to_time"></string>
<string name="_ago">%s पहल</string> <string name="_ago">%s पहल</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s क आपकपर तक पहच नह और आपकन: पत नह कर सकत. कि \'अजत उपयगकर\' स बचव किए आपक iPhone पथमिकत पहच परदन करन.</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s क आपकपर तक पहच नह और आपकन: पत नह कर सकत. कि \'अजत उपयगकर\' स बचव किए आपक iPhone पथमिकत पहच परदन करन.</string>
@ -184,7 +184,7 @@
<string name="conditioning_report_filtering_returns_no_data">िटर सई परिम नहि</string> <string name="conditioning_report_filtering_returns_no_data">िटर सई परिम नहि</string>
<string name="confirmation">करण</string> <string name="confirmation">करण</string>
<string name="contact">हमपरक कर</string> <string name="contact">हमपरक कर</string>
<string name="csv">CSV (इमट नहि सकत)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">आपक CSV फइल मइन एक अच तरह फट नह गई ह. कपय अपनइल ज सहयतम सपरक कर.</string> <string name="csv_bad_row_error_message">आपक CSV फइल मइन एक अच तरह फट नह गई ह. कपय अपनइल ज सहयतम सपरक कर.</string>
<string name="currency">कर</string> <string name="currency">कर</string>
<string name="current_month">वरतमन मह</string> <string name="current_month">वरतमन मह</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">Imposta una data di inizio per la sessione</string> <string name="session_missing_start_date">Imposta una data di inizio per la sessione</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">Valore iniziale</string> <string name="initial_value">Valore iniziale</string>
<string name="less_then_2_values_for_display">Non mostrabile, perché ci sono meno di due valori da visualizzare!</string> <string name="less_then_2_values_for_display">Non mostrabile, perché ci sono meno di due valori da visualizzare!</string>
<string name="invalid_object">L\'oggetto a cui stai cercando di accedere non è valido</string> <string name="invalid_object">L\'oggetto a cui stai cercando di accedere non è valido</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">Passa a Pro</string> <string name="pro_upgrade">Passa a Pro</string>
<string name="pro_purchase">Passa a Pro</string> <string name="pro_purchase">Passa a Pro</string>
<string name="free_trial">prova gratuita</string> <string name="free_trial">prova gratuita</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">Segui tutta la tua vita da pokerista aggiungendo tutti i dati desiderati</string> <string name="f_unlimited_desc">Segui tutta la tua vita da pokerista aggiungendo tutti i dati desiderati</string>
<string name="f_offline">Prima offline</string> <string name="f_offline">Prima offline</string>
<string name="f_offline_desc">Poker Analytics è disponibile sempre e i dati sono tuoi. Nota: presto aggiungeremo la funzione di esportazione e al momento spetta a te fare i backup. Grazie per la pazienza!</string> <string name="f_offline_desc">Poker Analytics è disponibile sempre e i dati sono tuoi. Nota: presto aggiungeremo la funzione di esportazione e al momento spetta a te fare i backup. Grazie per la pazienza!</string>
<string name="f_privacy">Privato</string> <string name="f_privacy">Privato</string>
<string name="f_privacy_desc">Non siamo proprietari dei server. Non abbiamo alcuna informazione sulle tue vincite né sulle tue perdite.</string> <string name="f_privacy_desc">Non siamo proprietari dei server. Non abbiamo alcuna informazione sulle tue vincite né sulle tue perdite.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">Cerchiamo di rispondere il prima possibile, in inglese o francese!</string> <string name="f_support_desc">Cerchiamo di rispondere il prima possibile, in inglese o francese!</string>
<string name="loading_please_wait">Caricamento in corso, attendere…</string> <string name="loading_please_wait">Caricamento in corso, attendere…</string>
<string name="new_report_step_type">Seleziona il tuo tipo di report</string> <string name="new_report_step_type">Seleziona il tuo tipo di report</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">Il filtro non può essere eliminato, perché è al momento selezionato.</string> <string name="filter_currently_selected">Il filtro non può essere eliminato, perché è al momento selezionato.</string>
<string name="custom_field">Campo personalizzato</string> <string name="custom_field">Campo personalizzato</string>
<string name="transaction_relationship_error">La voce è utilizzata in una o più transazioni…Prima elimina le transazioni collegate</string> <string name="transaction_relationship_error">La voce è utilizzata in una o più transazioni…Prima elimina le transazioni collegate</string>
<string name="imported">Imported</string>
<string name="iap_session_message">Hai raggiunto il limite massimo di sessioni gratuite. Abbonati per avere l\'uso illimitato, e non esitare a contattarci per farci sapere come ti trovi con la versione illimitata!</string> <string name="iap_session_message">Hai raggiunto il limite massimo di sessioni gratuite. Abbonati per avere l\'uso illimitato, e non esitare a contattarci per farci sapere come ti trovi con la versione illimitata!</string>
<string name="stacking_incoming">Staking in entrata</string> <string name="stacking_incoming">Staking in entrata</string>
<string name="stacking_outgoing">Staking in uscita</string> <string name="stacking_outgoing">Staking in uscita</string>
@ -47,12 +40,10 @@
<string name="suggestions">Suggerimenti di nomi</string> <string name="suggestions">Suggerimenti di nomi</string>
<string name="data_deleted">Dati eliminati</string> <string name="data_deleted">Dati eliminati</string>
<string name="end_date_not_possible">La data di fine deve essere successiva alla data di inizio</string> <string name="end_date_not_possible">La data di fine deve essere successiva alla data di inizio</string>
<string name="save">Save</string>
<string name="tournament_name">Nome torneo</string> <string name="tournament_name">Nome torneo</string>
<string name="tournament_names">Nomi torneo</string> <string name="tournament_names">Nomi torneo</string>
<string name="tournament_feature">Caratteristica torneo</string> <string name="tournament_feature">Caratteristica torneo</string>
<string name="tournament_features">Caratteristiche torneo</string> <string name="tournament_features">Caratteristiche torneo</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics è un\'app per monitorare le proprie partite a poker.\nL\'app funziona con un abbonamento annuale per uso illimitato, ma ogni utente riceve 10 sessioni + una prova gratuita per testare l\'app.</string> <string name="disclaimer">Poker Analytics è un\'app per monitorare le proprie partite a poker.\nL\'app funziona con un abbonamento annuale per uso illimitato, ma ogni utente riceve 10 sessioni + una prova gratuita per testare l\'app.</string>
<string name="iunderstand">Ho compreso</string> <string name="iunderstand">Ho compreso</string>
<string name="tournament_feature_empty_field_error">Assegna un nome a questa caratteristica di torneo</string> <string name="tournament_feature_empty_field_error">Assegna un nome a questa caratteristica di torneo</string>
@ -61,8 +52,6 @@
<string name="duplicate_tournament_name_error">Questo nome esiste già.</string> <string name="duplicate_tournament_name_error">Questo nome esiste già.</string>
<string name="bankroll_relationship_error_transactions">Una o più transazioni sono associate a questa posta di gioco. Prima elimina una o più transazioni associate.</string> <string name="bankroll_relationship_error_transactions">Una o più transazioni sono associate a questa posta di gioco. Prima elimina una o più transazioni associate.</string>
<string name="operation_type">Tipo di transazione</string> <string name="operation_type">Tipo di transazione</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">°</string> <string name="ordinal_suffix_first">°</string>
<string name="ordinal_suffix_second">°</string> <string name="ordinal_suffix_second">°</string>
<string name="ordinal_suffix_third">°</string> <string name="ordinal_suffix_third">°</string>
@ -84,6 +73,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour">Ora</string>
<string name="minute">Minuto</string>
<string name="more">Di Più</string>
<string name="lines">Linee</string>
<string name="f_unlimited">Illimitato</string>
<string name="f_support">Supporto</string>
<string name="imported">Importato</string>
<string name="save">Salva</string>
<string name="pending">In attesa di</string>
<string name="from_time">A partire dal</string>
<string name="to_time">Per</string>
<string name="_ago">%s fa</string> <string name="_ago">%s fa</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s non ha accesso ai tuoi contatti e non può recuperare il nome dei tuoi amici esistenti. Potresti consentire l\'accesso attraverso le preferenze di iPhone per evitare qualsiasi nome di \&quot;utente sconosciuto\&quot;.</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s non ha accesso ai tuoi contatti e non può recuperare il nome dei tuoi amici esistenti. Potresti consentire l\'accesso attraverso le preferenze di iPhone per evitare qualsiasi nome di \&quot;utente sconosciuto\&quot;.</string>
@ -184,7 +184,7 @@
<string name="conditioning_report_filtering_returns_no_data">Il filtraggio non ha dato alcun risultato</string> <string name="conditioning_report_filtering_returns_no_data">Il filtraggio non ha dato alcun risultato</string>
<string name="confirmation">Conferma</string> <string name="confirmation">Conferma</string>
<string name="contact">Contattaci</string> <string name="contact">Contattaci</string>
<string name="csv">CSV (non si può importare)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">Una delle linee nel tuo file CSV non è ben formata. Controlla il tuo file o contatta l\'assistenza.</string> <string name="csv_bad_row_error_message">Una delle linee nel tuo file CSV non è ben formata. Controlla il tuo file o contatta l\'assistenza.</string>
<string name="currency">Valuta</string> <string name="currency">Valuta</string>
<string name="current_month">Mese corrente</string> <string name="current_month">Mese corrente</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">セッションの開始日を設定してください</string> <string name="session_missing_start_date">セッションの開始日を設定してください</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">初期値</string> <string name="initial_value">初期値</string>
<string name="less_then_2_values_for_display">表示できません。表示するには最低2つの値が必要です。</string> <string name="less_then_2_values_for_display">表示できません。表示するには最低2つの値が必要です。</string>
<string name="invalid_object">アクセスしようとしているオブジェクトは無効です</string> <string name="invalid_object">アクセスしようとしているオブジェクトは無効です</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">プロにアップグレードする</string> <string name="pro_upgrade">プロにアップグレードする</string>
<string name="pro_purchase">プロになる</string> <string name="pro_purchase">プロになる</string>
<string name="free_trial">無料お試し</string> <string name="free_trial">無料お試し</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">お好きなだけデータを追加し、ポーカーライフをトラッキングしましょう</string> <string name="f_unlimited_desc">お好きなだけデータを追加し、ポーカーライフをトラッキングしましょう</string>
<string name="f_offline">オフラインファースト</string> <string name="f_offline">オフラインファースト</string>
<string name="f_offline_desc">Poker Analyticsはいつでもご利用できます。留意点:近々エクスポート機能が追加されます。現在はバックアップ機能をご使用ください。ご理解のほど、お願い申し上げます。</string> <string name="f_offline_desc">Poker Analyticsはいつでもご利用できます。留意点:近々エクスポート機能が追加されます。現在はバックアップ機能をご使用ください。ご理解のほど、お願い申し上げます。</string>
<string name="f_privacy">プライベート</string> <string name="f_privacy">プライベート</string>
<string name="f_privacy_desc">私達はサーバーを所有しておらず、ユーザー様の勝敗については何も把握しておりません。</string> <string name="f_privacy_desc">私達はサーバーを所有しておらず、ユーザー様の勝敗については何も把握しておりません。</string>
<string name="f_support">Support</string>
<string name="f_support_desc">出来るかぎり早く英語またはフランス語でご返信するよう努めます。</string> <string name="f_support_desc">出来るかぎり早く英語またはフランス語でご返信するよう努めます。</string>
<string name="loading_please_wait">ロード中です。しばらくお待ちください…</string> <string name="loading_please_wait">ロード中です。しばらくお待ちください…</string>
<string name="new_report_step_type">報告の種類を選んでください</string> <string name="new_report_step_type">報告の種類を選んでください</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">フィルターは現在選択中のため削除できません。</string> <string name="filter_currently_selected">フィルターは現在選択中のため削除できません。</string>
<string name="custom_field">カスタムフィールド</string> <string name="custom_field">カスタムフィールド</string>
<string name="transaction_relationship_error">アイテムは一つまたは複数の取引で使用中です。…まずは該当する取引を削除してください。</string> <string name="transaction_relationship_error">アイテムは一つまたは複数の取引で使用中です。…まずは該当する取引を削除してください。</string>
<string name="imported">Imported</string>
<string name="iap_session_message">無料セッションの利用限度に達しました。無制限利用のサブスクリプションを購 <string name="iap_session_message">無料セッションの利用限度に達しました。無制限利用のサブスクリプションを購
入し、現在の感想をお聞かせください。</string> 入し、現在の感想をお聞かせください。</string>
<string name="stacking_incoming">ステーキングを受け取っています</string> <string name="stacking_incoming">ステーキングを受け取っています</string>
@ -50,12 +43,10 @@
<string name="suggestions">名前の候補</string> <string name="suggestions">名前の候補</string>
<string name="data_deleted">データは削除されました</string> <string name="data_deleted">データは削除されました</string>
<string name="end_date_not_possible">終了日は開始日以降を選んでください</string> <string name="end_date_not_possible">終了日は開始日以降を選んでください</string>
<string name="save">Save</string>
<string name="tournament_name">トーナメント名</string> <string name="tournament_name">トーナメント名</string>
<string name="tournament_names">トーナメント名</string> <string name="tournament_names">トーナメント名</string>
<string name="tournament_feature">トーナメントの機能</string> <string name="tournament_feature">トーナメントの機能</string>
<string name="tournament_features">トーナメントの機能</string> <string name="tournament_features">トーナメントの機能</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analyticsはポーカーのトラッキングアプリです。\nアプリは年間サブスクリプションで無制限でご利用できますが、アプリのお試し用に10のセッションと無料期間があります。</string> <string name="disclaimer">Poker Analyticsはポーカーのトラッキングアプリです。\nアプリは年間サブスクリプションで無制限でご利用できますが、アプリのお試し用に10のセッションと無料期間があります。</string>
<string name="iunderstand">分かりました</string> <string name="iunderstand">分かりました</string>
<string name="tournament_feature_empty_field_error">このトーナメントの機能に名前をつけてください</string> <string name="tournament_feature_empty_field_error">このトーナメントの機能に名前をつけてください</string>
@ -65,8 +56,6 @@
<string name="bankroll_relationship_error_transactions">このバンクロールは一つまたは複数の取引に賭けられています。まずは該当す <string name="bankroll_relationship_error_transactions">このバンクロールは一つまたは複数の取引に賭けられています。まずは該当す
る取引を削除してください。</string> る取引を削除してください。</string>
<string name="operation_type">取引の種類</string> <string name="operation_type">取引の種類</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">st</string> <string name="ordinal_suffix_first">st</string>
<string name="ordinal_suffix_second">nd</string> <string name="ordinal_suffix_second">nd</string>
<string name="ordinal_suffix_third">rd</string> <string name="ordinal_suffix_third">rd</string>
@ -88,6 +77,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour"></string>
<string name="minute"></string>
<string name="more">もっと</string>
<string name="lines"></string>
<string name="f_unlimited">無制限</string>
<string name="f_support">サポート</string>
<string name="imported">輸入</string>
<string name="save">セーブ</string>
<string name="pending">保留中</string>
<string name="from_time">から</string>
<string name="to_time"></string>
<string name="_ago">%s 前</string> <string name="_ago">%s 前</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s では、あなたの連絡先にアクセスできないため、既存のお友達の名前を取得できません。「不明なユーザー」名を回避するには、iPhone のユーザー設定からアクセス権限を付与してください。</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s では、あなたの連絡先にアクセスできないため、既存のお友達の名前を取得できません。「不明なユーザー」名を回避するには、iPhone のユーザー設定からアクセス権限を付与してください。</string>
@ -188,7 +188,7 @@
<string name="conditioning_report_filtering_returns_no_data">フィルタリングでは結果が戻されませんでした</string> <string name="conditioning_report_filtering_returns_no_data">フィルタリングでは結果が戻されませんでした</string>
<string name="confirmation">確認</string> <string name="confirmation">確認</string>
<string name="contact">ご連絡ください</string> <string name="contact">ご連絡ください</string>
<string name="csv">CSV (インポートできません)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">CSV ファイルのいずれかの行が正しく形成されていません。ファイルをご確認いただくが、サポートまでお問い合わせください。</string> <string name="csv_bad_row_error_message">CSV ファイルのいずれかの行が正しく形成されていません。ファイルをご確認いただくが、サポートまでお問い合わせください。</string>
<string name="currency">通貨</string> <string name="currency">通貨</string>
<string name="current_month">今月</string> <string name="current_month">今月</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">Defina uma data de início para a sessão</string> <string name="session_missing_start_date">Defina uma data de início para a sessão</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">Valor inicial</string> <string name="initial_value">Valor inicial</string>
<string name="less_then_2_values_for_display">Não é possível exibir porque há menos de dois valores para exibir!</string> <string name="less_then_2_values_for_display">Não é possível exibir porque há menos de dois valores para exibir!</string>
<string name="invalid_object">O objeto que você está tentando acessar é inválido</string> <string name="invalid_object">O objeto que você está tentando acessar é inválido</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">Fazer upgrade para Pro</string> <string name="pro_upgrade">Fazer upgrade para Pro</string>
<string name="pro_purchase">Seja Pro</string> <string name="pro_purchase">Seja Pro</string>
<string name="free_trial">avaliação gratuita</string> <string name="free_trial">avaliação gratuita</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">Monitore toda a sua vida no pôquer com quantos dados você quiser</string> <string name="f_unlimited_desc">Monitore toda a sua vida no pôquer com quantos dados você quiser</string>
<string name="f_offline">Offline primeiro</string> <string name="f_offline">Offline primeiro</string>
<string name="f_offline_desc">O Poker Analytics está disponível sempre e os dados são seus. Nota: Adicionaremos a capacidade de exportar em breve e você é responsável por seus backups no momento. Agradecemos a paciência!</string> <string name="f_offline_desc">O Poker Analytics está disponível sempre e os dados são seus. Nota: Adicionaremos a capacidade de exportar em breve e você é responsável por seus backups no momento. Agradecemos a paciência!</string>
<string name="f_privacy">Privado</string> <string name="f_privacy">Privado</string>
<string name="f_privacy_desc">Não temos servidores. Não sabemos nada sobre suas vitórias e derrotas.</string> <string name="f_privacy_desc">Não temos servidores. Não sabemos nada sobre suas vitórias e derrotas.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">Tentamos responder o mais rápido possível, em inglês ou francês!</string> <string name="f_support_desc">Tentamos responder o mais rápido possível, em inglês ou francês!</string>
<string name="loading_please_wait">Carregando, aguarde…</string> <string name="loading_please_wait">Carregando, aguarde…</string>
<string name="new_report_step_type">Selecione seu tipo de relatório</string> <string name="new_report_step_type">Selecione seu tipo de relatório</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">O filtro não pode ser excluído porque está selecionado no momento.</string> <string name="filter_currently_selected">O filtro não pode ser excluído porque está selecionado no momento.</string>
<string name="custom_field">Campo personalizado</string> <string name="custom_field">Campo personalizado</string>
<string name="transaction_relationship_error">O item é usado em uma ou mais transações…Exclua as transações vinculadas primeiro</string> <string name="transaction_relationship_error">O item é usado em uma ou mais transações…Exclua as transações vinculadas primeiro</string>
<string name="imported">Imported</string>
<string name="iap_session_message">Você atingiu o número máximo de sessões gratuitas. Assine para usar sem limites e não deixe de nos contar o que você está achando até agora da experiência!</string> <string name="iap_session_message">Você atingiu o número máximo de sessões gratuitas. Assine para usar sem limites e não deixe de nos contar o que você está achando até agora da experiência!</string>
<string name="stacking_incoming">Staking chegando</string> <string name="stacking_incoming">Staking chegando</string>
<string name="stacking_outgoing">Staking saindo</string> <string name="stacking_outgoing">Staking saindo</string>
@ -47,12 +40,10 @@
<string name="suggestions">Sugestões de nome</string> <string name="suggestions">Sugestões de nome</string>
<string name="data_deleted">Dados excluídos</string> <string name="data_deleted">Dados excluídos</string>
<string name="end_date_not_possible">A data de término deve ser depois da data de início</string> <string name="end_date_not_possible">A data de término deve ser depois da data de início</string>
<string name="save">Save</string>
<string name="tournament_name">Nome do torneio</string> <string name="tournament_name">Nome do torneio</string>
<string name="tournament_names">Nomes dos torneios</string> <string name="tournament_names">Nomes dos torneios</string>
<string name="tournament_feature">Função do torneio</string> <string name="tournament_feature">Função do torneio</string>
<string name="tournament_features">Funções do torneio</string> <string name="tournament_features">Funções do torneio</string>
<string name="pending">Pending</string>
<string name="disclaimer">O Poker Analytics é um app de monitoramento.\nO app funciona com uma assinatura anual com uso ilimitado, mas você tem 10 sessões + teste grátis para testar o app.</string> <string name="disclaimer">O Poker Analytics é um app de monitoramento.\nO app funciona com uma assinatura anual com uso ilimitado, mas você tem 10 sessões + teste grátis para testar o app.</string>
<string name="iunderstand">Entendi</string> <string name="iunderstand">Entendi</string>
<string name="tournament_feature_empty_field_error">Você precisa dar um nome para esta função do torneio</string> <string name="tournament_feature_empty_field_error">Você precisa dar um nome para esta função do torneio</string>
@ -61,8 +52,6 @@
<string name="duplicate_tournament_name_error">Este nome já existe.</string> <string name="duplicate_tournament_name_error">Este nome já existe.</string>
<string name="bankroll_relationship_error_transactions">Uma ou mais transações associadas com esta banca. Exclua as transações vinculadas primeiro.</string> <string name="bankroll_relationship_error_transactions">Uma ou mais transações associadas com esta banca. Exclua as transações vinculadas primeiro.</string>
<string name="operation_type">Tipo de transação</string> <string name="operation_type">Tipo de transação</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">º</string> <string name="ordinal_suffix_first">º</string>
<string name="ordinal_suffix_second">º</string> <string name="ordinal_suffix_second">º</string>
<string name="ordinal_suffix_third">º</string> <string name="ordinal_suffix_third">º</string>
@ -84,6 +73,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour">Hora</string>
<string name="minute">Minuto</string>
<string name="more">Mais</string>
<string name="lines">Linhas</string>
<string name="f_unlimited">Ilimitado</string>
<string name="f_support">Apoio, suporte</string>
<string name="imported">Importado</string>
<string name="save">Salve</string>
<string name="pending">Pendente</string>
<string name="from_time">De</string>
<string name="to_time">Para</string>
<string name="_ago">%s atrás</string> <string name="_ago">%s atrás</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">O %s não possui acesso à lista de contatos e não pode obter os nomes dos seus amigos. Você pode permitir o acesso nos ajustes dos iPhone para evitar exibir \'usuário desconhecido\' no lugar do nome.</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">O %s não possui acesso à lista de contatos e não pode obter os nomes dos seus amigos. Você pode permitir o acesso nos ajustes dos iPhone para evitar exibir \'usuário desconhecido\' no lugar do nome.</string>
@ -184,7 +184,7 @@
<string name="conditioning_report_filtering_returns_no_data">O filtro não apresentou nenhum resultado</string> <string name="conditioning_report_filtering_returns_no_data">O filtro não apresentou nenhum resultado</string>
<string name="confirmation">Confirmação</string> <string name="confirmation">Confirmação</string>
<string name="contact">Contate-nos</string> <string name="contact">Contate-nos</string>
<string name="csv">CSV (Não pode ser importado)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">Uma das linhas do seu arquivo CSV não está no formato correto. Por favor, verifique o seu arquivo ou contate o suporte.</string> <string name="csv_bad_row_error_message">Uma das linhas do seu arquivo CSV não está no formato correto. Por favor, verifique o seu arquivo ou contate o suporte.</string>
<string name="currency">Moeda</string> <string name="currency">Moeda</string>
<string name="current_month">Mês atual</string> <string name="current_month">Mês atual</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">Пожалуйста, установите дату начала сессии</string> <string name="session_missing_start_date">Пожалуйста, установите дату начала сессии</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">Начальное значение</string> <string name="initial_value">Начальное значение</string>
<string name="less_then_2_values_for_display">Невозможно показать, потому что для отображения меньше двух значений!</string> <string name="less_then_2_values_for_display">Невозможно показать, потому что для отображения меньше двух значений!</string>
<string name="invalid_object">Объект, к которому пытаются получить доступ, недействителен.</string> <string name="invalid_object">Объект, к которому пытаются получить доступ, недействителен.</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">Повысить категорию до Pro</string> <string name="pro_upgrade">Повысить категорию до Pro</string>
<string name="pro_purchase">Перейти на Pro</string> <string name="pro_purchase">Перейти на Pro</string>
<string name="free_trial">бесплатное опробование</string> <string name="free_trial">бесплатное опробование</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">Отслеживайте всю свою жизнь в покере, добавляя столько данных, сколько хотите</string> <string name="f_unlimited_desc">Отслеживайте всю свою жизнь в покере, добавляя столько данных, сколько хотите</string>
<string name="f_offline">Сначала автономно</string> <string name="f_offline">Сначала автономно</string>
<string name="f_offline_desc">Poker Analytics доступно в любое время, а данные - ваши. Примечание: вскоре мы добавим возможности экспорта, но в настоящее время вы отвечаете за резервное копирование. Спасибо за ваше терпение!</string> <string name="f_offline_desc">Poker Analytics доступно в любое время, а данные - ваши. Примечание: вскоре мы добавим возможности экспорта, но в настоящее время вы отвечаете за резервное копирование. Спасибо за ваше терпение!</string>
<string name="f_privacy">Частное</string> <string name="f_privacy">Частное</string>
<string name="f_privacy_desc">Мы не владеем серверами. Мы ничего не знаем о ваших выигрышах и проигрышах.</string> <string name="f_privacy_desc">Мы не владеем серверами. Мы ничего не знаем о ваших выигрышах и проигрышах.</string>
<string name="f_support">Support</string>
<string name="f_support_desc">Мы стараемся ответить как можно быстрее, по-английски или по-французски!</string> <string name="f_support_desc">Мы стараемся ответить как можно быстрее, по-английски или по-французски!</string>
<string name="loading_please_wait">Загрузка, пожалуйста, подождите…</string> <string name="loading_please_wait">Загрузка, пожалуйста, подождите…</string>
<string name="new_report_step_type">Выберите свой тип отчёта</string> <string name="new_report_step_type">Выберите свой тип отчёта</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">Фильтр не может быть удален, так как он выбран в данный момент.</string> <string name="filter_currently_selected">Фильтр не может быть удален, так как он выбран в данный момент.</string>
<string name="custom_field">Пользовательское поле</string> <string name="custom_field">Пользовательское поле</string>
<string name="transaction_relationship_error">Элемент используется в одной или нескольких транзакциях…Пожалуйста, сначала удалите связанные транзакции</string> <string name="transaction_relationship_error">Элемент используется в одной или нескольких транзакциях…Пожалуйста, сначала удалите связанные транзакции</string>
<string name="imported">Imported</string>
<string name="iap_session_message">Вы достигли максимального количества бесплатных сессий. Пожалуйста, подпишитесь на неограниченное использование и без колебаний сообщайте нам, что вы думаете о своих текущих впечатлениях!</string> <string name="iap_session_message">Вы достигли максимального количества бесплатных сессий. Пожалуйста, подпишитесь на неограниченное использование и без колебаний сообщайте нам, что вы думаете о своих текущих впечатлениях!</string>
<string name="stacking_incoming">Ставка прибывает</string> <string name="stacking_incoming">Ставка прибывает</string>
<string name="stacking_outgoing">Ставка убывает</string> <string name="stacking_outgoing">Ставка убывает</string>
@ -47,12 +40,10 @@
<string name="suggestions">Предложения по наименованию</string> <string name="suggestions">Предложения по наименованию</string>
<string name="data_deleted">Данные удалены</string> <string name="data_deleted">Данные удалены</string>
<string name="end_date_not_possible">Дата окончания должна быть после даты начала</string> <string name="end_date_not_possible">Дата окончания должна быть после даты начала</string>
<string name="save">Save</string>
<string name="tournament_name">Название турнира</string> <string name="tournament_name">Название турнира</string>
<string name="tournament_names">Названия турниров</string> <string name="tournament_names">Названия турниров</string>
<string name="tournament_feature">Функция турнира</string> <string name="tournament_feature">Функция турнира</string>
<string name="tournament_features">Функции турниров</string> <string name="tournament_features">Функции турниров</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics - это приложение для отслеживания покера.\nПриложение работает по годовой подписке на неограниченное использование, но вы получаете 10 сессий + бесплатную пробную версию для тестирования приложения.</string> <string name="disclaimer">Poker Analytics - это приложение для отслеживания покера.\nПриложение работает по годовой подписке на неограниченное использование, но вы получаете 10 сессий + бесплатную пробную версию для тестирования приложения.</string>
<string name="iunderstand">Вас понял(а)</string> <string name="iunderstand">Вас понял(а)</string>
<string name="tournament_feature_empty_field_error">Нужно дать название этой турнирной функции</string> <string name="tournament_feature_empty_field_error">Нужно дать название этой турнирной функции</string>
@ -61,8 +52,6 @@
<string name="duplicate_tournament_name_error">Это название уже существует.</string> <string name="duplicate_tournament_name_error">Это название уже существует.</string>
<string name="bankroll_relationship_error_transactions">С этой финансовой операцией связана одна или несколько транзакций, пожалуйста, сначала удалите связанную(ые) транзакцию(ы).</string> <string name="bankroll_relationship_error_transactions">С этой финансовой операцией связана одна или несколько транзакций, пожалуйста, сначала удалите связанную(ые) транзакцию(ы).</string>
<string name="operation_type">Тип транзакции</string> <string name="operation_type">Тип транзакции</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first"></string> <string name="ordinal_suffix_first"></string>
<string name="ordinal_suffix_second"></string> <string name="ordinal_suffix_second"></string>
<string name="ordinal_suffix_third"></string> <string name="ordinal_suffix_third"></string>
@ -84,6 +73,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour">Час</string>
<string name="minute">минут</string>
<string name="more">Больше</string>
<string name="lines">линии</string>
<string name="f_unlimited">неограниченный</string>
<string name="f_support">Поддержка</string>
<string name="imported">импортный</string>
<string name="save">Сохранить</string>
<string name="pending">В ожидании</string>
<string name="from_time">От</string>
<string name="to_time">к</string>
<string name="_ago">%s назад</string> <string name="_ago">%s назад</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s не имеет доступа к адресной книге и не может определить имена выбранных вами друзей. Предоставьте доступ к контактам в настройках телефона чтобы исключить имена \'неизвестный пользователь\'</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s не имеет доступа к адресной книге и не может определить имена выбранных вами друзей. Предоставьте доступ к контактам в настройках телефона чтобы исключить имена \'неизвестный пользователь\'</string>
@ -184,7 +184,7 @@
<string name="conditioning_report_filtering_returns_no_data">Не найдено результатов после фильтрации</string> <string name="conditioning_report_filtering_returns_no_data">Не найдено результатов после фильтрации</string>
<string name="confirmation">Подтверждение</string> <string name="confirmation">Подтверждение</string>
<string name="contact">Напишите нам</string> <string name="contact">Напишите нам</string>
<string name="csv">CSV (Импорт невозможен)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">Одна из строк в вашем файле CSV отформатирована некорректно. Пожалуйста проверьте ваш файл или свяжитесь со службой поддержки.</string> <string name="csv_bad_row_error_message">Одна из строк в вашем файле CSV отформатирована некорректно. Пожалуйста проверьте ваш файл или свяжитесь со службой поддержки.</string>
<string name="currency">Валюта</string> <string name="currency">Валюта</string>
<string name="current_month">Текущий месяц</string> <string name="current_month">Текущий месяц</string>

@ -2,10 +2,6 @@
<string name="app_name">Poker Analytics</string> <string name="app_name">Poker Analytics</string>
<string name="session_missing_start_date">请设置该进程的开始日期</string> <string name="session_missing_start_date">请设置该进程的开始日期</string>
<string name="hour">Hour</string>
<string name="minute">Minute</string>
<string name="more">More</string>
<string name="lines">Lines</string>
<string name="initial_value">初始值</string> <string name="initial_value">初始值</string>
<string name="less_then_2_values_for_display">不能显示,因为要显示的值少于两个!</string> <string name="less_then_2_values_for_display">不能显示,因为要显示的值少于两个!</string>
<string name="invalid_object">您试图访问的对象无效</string> <string name="invalid_object">您试图访问的对象无效</string>
@ -14,13 +10,11 @@
<string name="pro_upgrade">升级到专业版</string> <string name="pro_upgrade">升级到专业版</string>
<string name="pro_purchase">获取专业版</string> <string name="pro_purchase">获取专业版</string>
<string name="free_trial">免费试用</string> <string name="free_trial">免费试用</string>
<string name="f_unlimited">Unlimited</string>
<string name="f_unlimited_desc">通过添加尽可能多的数据来追踪您的所有扑克游戏</string> <string name="f_unlimited_desc">通过添加尽可能多的数据来追踪您的所有扑克游戏</string>
<string name="f_offline">先离线</string> <string name="f_offline">先离线</string>
<string name="f_offline_desc">Poker Analytics随时可用且该数据属于你。注意:我们将很快添加导出功能,您目前负责备份。谢谢你的耐心!</string> <string name="f_offline_desc">Poker Analytics随时可用且该数据属于你。注意:我们将很快添加导出功能,您目前负责备份。谢谢你的耐心!</string>
<string name="f_privacy">私人</string> <string name="f_privacy">私人</string>
<string name="f_privacy_desc">我们没有服务器。我们对你的输赢一无所知。</string> <string name="f_privacy_desc">我们没有服务器。我们对你的输赢一无所知。</string>
<string name="f_support">Support</string>
<string name="f_support_desc">我们尽快用英语或法语回答!</string> <string name="f_support_desc">我们尽快用英语或法语回答!</string>
<string name="loading_please_wait">正在加载,请等待…</string> <string name="loading_please_wait">正在加载,请等待…</string>
<string name="new_report_step_type">选择您的报告类型</string> <string name="new_report_step_type">选择您的报告类型</string>
@ -36,7 +30,6 @@
<string name="filter_currently_selected">无法删除该筛选条件,因为它目前已被选取。</string> <string name="filter_currently_selected">无法删除该筛选条件,因为它目前已被选取。</string>
<string name="custom_field">自定义字段</string> <string name="custom_field">自定义字段</string>
<string name="transaction_relationship_error">该项目用于一个或多个交易…请先删除链接的交易</string> <string name="transaction_relationship_error">该项目用于一个或多个交易…请先删除链接的交易</string>
<string name="imported">Imported</string>
<string name="iap_session_message">您已经达到了免费进程的最大数量。请订阅无限制使用,不要犹豫,告诉我们您对目前的体验感觉如何!</string> <string name="iap_session_message">您已经达到了免费进程的最大数量。请订阅无限制使用,不要犹豫,告诉我们您对目前的体验感觉如何!</string>
<string name="stacking_incoming">接收的赌注</string> <string name="stacking_incoming">接收的赌注</string>
<string name="stacking_outgoing">发出的赌注</string> <string name="stacking_outgoing">发出的赌注</string>
@ -47,12 +40,10 @@
<string name="suggestions">命名建议</string> <string name="suggestions">命名建议</string>
<string name="data_deleted">数据已删除</string> <string name="data_deleted">数据已删除</string>
<string name="end_date_not_possible">结束日期应在开始日期后</string> <string name="end_date_not_possible">结束日期应在开始日期后</string>
<string name="save">Save</string>
<string name="tournament_name">锦标赛名称</string> <string name="tournament_name">锦标赛名称</string>
<string name="tournament_names">锦标赛名称</string> <string name="tournament_names">锦标赛名称</string>
<string name="tournament_feature">锦标赛功能</string> <string name="tournament_feature">锦标赛功能</string>
<string name="tournament_features">锦标赛功能</string> <string name="tournament_features">锦标赛功能</string>
<string name="pending">Pending</string>
<string name="disclaimer">Poker Analytics是一款扑克追踪应用。该应用可包年订阅获取无限制使用,但你可以获得10次进程+1次免费试用来测试本应用。</string> <string name="disclaimer">Poker Analytics是一款扑克追踪应用。该应用可包年订阅获取无限制使用,但你可以获得10次进程+1次免费试用来测试本应用。</string>
<string name="iunderstand">我理解</string> <string name="iunderstand">我理解</string>
<string name="tournament_feature_empty_field_error">您需要为此锦标赛功能指定一个名称</string> <string name="tournament_feature_empty_field_error">您需要为此锦标赛功能指定一个名称</string>
@ -61,8 +52,6 @@
<string name="duplicate_tournament_name_error">此名称已存在。</string> <string name="duplicate_tournament_name_error">此名称已存在。</string>
<string name="bankroll_relationship_error_transactions">一个或多个交易与此资金相关,请先删除相关交易。</string> <string name="bankroll_relationship_error_transactions">一个或多个交易与此资金相关,请先删除相关交易。</string>
<string name="operation_type">交易类型</string> <string name="operation_type">交易类型</string>
<string name="from_time">From</string>
<string name="to_time">To</string>
<string name="ordinal_suffix_first">.</string> <string name="ordinal_suffix_first">.</string>
<string name="ordinal_suffix_second">.</string> <string name="ordinal_suffix_second">.</string>
<string name="ordinal_suffix_third">.</string> <string name="ordinal_suffix_third">.</string>
@ -83,6 +72,17 @@
<string name="street_flop">Flop</string> <string name="street_flop">Flop</string>
<string name="street_turn">Turn</string> <string name="street_turn">Turn</string>
<string name="street_river">River</string> <string name="street_river">River</string>
<string name="hour">小时</string>
<string name="minute">分钟</string>
<string name="more">更多</string>
<string name="lines">线数</string>
<string name="f_unlimited">无限</string>
<string name="f_support">支持</string>
<string name="imported">进口的</string>
<string name="save">保存</string>
<string name="pending">待定</string>
<string name="from_time"></string>
<string name="to_time"></string>
<string name="_ago">%s前</string> <string name="_ago">%s前</string>
<string name="_doesn_t_have_access_to_your_contacts_alert_message">%s不能访问你的联系人且不能检索你的现有好友姓名。通过iPhone首选项可授权防止任何\'陌生用户\'名访问。</string> <string name="_doesn_t_have_access_to_your_contacts_alert_message">%s不能访问你的联系人且不能检索你的现有好友姓名。通过iPhone首选项可授权防止任何\'陌生用户\'名访问。</string>
@ -169,7 +169,7 @@
<string name="comparison">比较</string> <string name="comparison">比较</string>
<string name="confirmation">确认</string> <string name="confirmation">确认</string>
<string name="contact">联系我们</string> <string name="contact">联系我们</string>
<string name="csv">CSV(无法导入)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">CSV文件中的线之一不合适。请核查你的文件或联系支持团队。</string> <string name="csv_bad_row_error_message">CSV文件中的线之一不合适。请核查你的文件或联系支持团队。</string>
<string name="currency">货币</string> <string name="currency">货币</string>
<string name="current_month">本月</string> <string name="current_month">本月</string>

@ -11,7 +11,6 @@
<string name="hour">Hour</string> <string name="hour">Hour</string>
<string name="minute">Minute</string> <string name="minute">Minute</string>
<string name="more">More</string> <string name="more">More</string>
<string name="variant">Variant</string>
<string name="lines">Lines</string> <string name="lines">Lines</string>
<string name="initial_value">Initial Value</string> <string name="initial_value">Initial Value</string>
<string name="less_then_2_values_for_display">Can\'t show because there is less than two values to display!</string> <string name="less_then_2_values_for_display">Can\'t show because there is less than two values to display!</string>
@ -45,11 +44,12 @@
<string name="transaction_relationship_error">The item is used in one or more transactions&#8230;Please delete the linked transactions first</string> <string name="transaction_relationship_error">The item is used in one or more transactions&#8230;Please delete the linked transactions first</string>
<string name="imported">Imported</string> <string name="imported">Imported</string>
<string name="iap_session_message">You\'ve reached the maximum number of free sessions. Please subscribe for unlimited use and don\'t hesitate to tell us how you feel about your current experience!</string> <string name="iap_session_message">You\'ve reached the maximum number of free sessions. Please subscribe for unlimited use and don\'t hesitate to tell us how you feel about your current experience!</string>
<string name="stacking_incoming">Stacking incoming</string> <string name="stacking_incoming">Staking incoming</string>
<string name="stacking_outgoing">Stacking outgoing</string> <string name="stacking_outgoing">Staking outgoing</string>
<string name="import_error">There has been an issue with the import. Please check out your file or contact the support!</string> <string name="import_error">There has been an issue with the import. Please check out your file or contact the support!</string>
<string name="subscription_text">Subscription terms of use:\n• When subscribing, the free trial prevents you from being charged until the period ends\n• At the end of the free trial, you will be automatically charged the yearly subscription amount\n• A subscription automatically renews unless canceled\n• You can manage your subscription by going in the app "More" tab, then "Subscription"</string>
<string name="show_fullscreen">Show full screen</string>
<string name="address">Address</string>
<string name="suggestions">Naming suggestions</string> <string name="suggestions">Naming suggestions</string>
<string name="data_deleted">Data deleted</string> <string name="data_deleted">Data deleted</string>
<string name="end_date_not_possible">The end date should be after the start date</string> <string name="end_date_not_possible">The end date should be after the start date</string>
@ -67,7 +67,6 @@
<string name="duplicate_tournament_name_error">This name already exists.</string> <string name="duplicate_tournament_name_error">This name already exists.</string>
<string name="bankroll_relationship_error_transactions">One or more transactions are associated with this bankroll, please delete the linked transaction(s) first.</string> <string name="bankroll_relationship_error_transactions">One or more transactions are associated with this bankroll, please delete the linked transaction(s) first.</string>
<string name="operation_type">Transaction type</string> <string name="operation_type">Transaction type</string>
<string name="from_time">From</string> <string name="from_time">From</string>
<string name="to_time">To</string> <string name="to_time">To</string>
<string name="ordinal_suffix_first">st</string> <string name="ordinal_suffix_first">st</string>
@ -79,8 +78,6 @@
<string name="new_tournament_feature">New tournament feature</string> <string name="new_tournament_feature">New tournament feature</string>
<string name="new_filter">New filter</string> <string name="new_filter">New filter</string>
<!-- Translated --> <!-- Translated -->
<string name="_ago">%s ago</string> <string name="_ago">%s ago</string>
@ -182,7 +179,7 @@
<string name="conditioning_report_filtering_returns_no_data">Filtering did not yield any results</string> <string name="conditioning_report_filtering_returns_no_data">Filtering did not yield any results</string>
<string name="confirmation">Confirmation</string> <string name="confirmation">Confirmation</string>
<string name="contact">Contact us</string> <string name="contact">Contact us</string>
<string name="csv">CSV (Cannot be imported)</string> <string name="csv">CSV</string>
<string name="csv_bad_row_error_message">One of the lines in your CSV file is not well formed. Please check your file or contact the support.</string> <string name="csv_bad_row_error_message">One of the lines in your CSV file is not well formed. Please check your file or contact the support.</string>
<string name="currency">Currency</string> <string name="currency">Currency</string>
<string name="current_month">Current month</string> <string name="current_month">Current month</string>
@ -666,7 +663,6 @@
<string name="intermediate_sub_short_title">Semi-Pro</string> <string name="intermediate_sub_short_title">Semi-Pro</string>
<string name="pro_sub_short_title">Pro</string> <string name="pro_sub_short_title">Pro</string>
<string name="subscription_details">Subscription terms</string> <string name="subscription_details">Subscription terms</string>
<string name="subscription_text">Subscription terms of use:\n• Payment will be charged to iTunes Account at confirmation of purchase\n• Subscription automatically renews unless auto-renew is turned off at least 24-hours before the end of the current period\n• Account will be charged for renewal within 24-hours prior to the end of the current period, and identify the cost of the renewal\n• Subscriptions may be managed by the user and auto-renewal may be turned off by going to the user\'s Account Settings after purchase\n• Any unused portion of a free trial period, if offered, will be forfeited when the user purchases a subscription to that publication, where applicable</string>
<string name="privacy_policy">Privacy policy</string> <string name="privacy_policy">Privacy policy</string>
<string name="bug_report_message">We\'re truly sorry, but something is wrong here&#8230;You may be waiting for iCloud sync. Please wait and retry later. Would you mind sending us a report explaining your current state to help us solve this issue?</string> <string name="bug_report_message">We\'re truly sorry, but something is wrong here&#8230;You may be waiting for iCloud sync. Please wait and retry later. Would you mind sending us a report explaining your current state to help us solve this issue?</string>
<string name="longtap_to_duplicate">Tap and hold on a session to duplicate it!</string> <string name="longtap_to_duplicate">Tap and hold on a session to duplicate it!</string>
@ -762,7 +758,6 @@
<string name="do_you_really_to_delete_this_game">Do you really want to delete this game?</string> <string name="do_you_really_to_delete_this_game">Do you really want to delete this game?</string>
<string name="comments">Comments</string> <string name="comments">Comments</string>
<string name="bb_ante_option">Big Blind Ante</string> <string name="bb_ante_option">Big Blind Ante</string>
<string name="show_fullscreen">Show full screen</string>
<!-- Info.plist --> <!-- Info.plist -->
@ -778,6 +773,8 @@
<string name="join_discord">Join us on Discord!</string> <string name="join_discord">Join us on Discord!</string>
<string name="discord_feed_message">We\'ve opened our Discord channel! Come to hang out, talk about poker or about the app!</string> <string name="discord_feed_message">We\'ve opened our Discord channel! Come to hang out, talk about poker or about the app!</string>
<string name="good_for_you">Good for you!</string> <string name="good_for_you">Good for you!</string>
<string name="sessions_csv">Sessions (CSV)</string>
<string name="transactions_csv">Transactions (CSV)</string>
<string name="posts_sb">posts</string> <string name="posts_sb">posts</string>
<string name="post_bb">posts</string> <string name="post_bb">posts</string>

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path
name="files"
path="." />
<external-path <files-path name="files" path="." />
name="external_files"
path="." /> <external-path name="external_files" path="." />
<!-- <cache-path name="name" path="path" />-->
</paths> </paths>

@ -1,5 +1,6 @@
package net.pokeranalytics.android package net.pokeranalytics.android
import net.pokeranalytics.android.util.CSVNumberFormat
import net.pokeranalytics.android.util.Parser import net.pokeranalytics.android.util.Parser
import net.pokeranalytics.android.util.extensions.formatted import net.pokeranalytics.android.util.extensions.formatted
import net.pokeranalytics.android.util.extensions.kmbFormatted import net.pokeranalytics.android.util.extensions.kmbFormatted
@ -56,4 +57,13 @@ class BasicUnitTest : RealmUnitTest() {
} }
@Test
fun testCSVFormatter() {
val str1 = CSVNumberFormat.format(1111.2567)
Assert.assertEquals("1111.2567", str1)
val str2 = CSVNumberFormat.format(1000)
Assert.assertEquals("1000", str2)
}
} }

@ -1 +1,5 @@
<<<<<<< HEAD
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":79,"versionName":"3.0","enabled":true,"outputFile":"PokerAnalytics_3.0(79)_200428_1456_release.apk","fullName":"standardRelease","baseName":"standard-release","dirName":""},"path":"PokerAnalytics_3.0(79)_200428_1456_release.apk","properties":{}}] [{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":79,"versionName":"3.0","enabled":true,"outputFile":"PokerAnalytics_3.0(79)_200428_1456_release.apk","fullName":"standardRelease","baseName":"standard-release","dirName":""},"path":"PokerAnalytics_3.0(79)_200428_1456_release.apk","properties":{}}]
=======
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":84,"versionName":"2.4.3","enabled":true,"outputFile":"PokerAnalytics_2.4.3(84)_200526_1106_release.apk","fullName":"standardRelease","baseName":"standard-release","dirName":""},"path":"PokerAnalytics_2.4.3(84)_200526_1106_release.apk","properties":{}}]
>>>>>>> master

@ -1,4 +1,4 @@
#Wed Mar 04 11:24:53 CET 2020 #Wed May 13 12:21:50 CEST 2020
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

Loading…
Cancel
Save