Merge branch 'dev' of gitlab.com:stax-river/poker-analytics into dev

dev
Aurelien Hubert 7 years ago
commit c77b739eb5
  1. 8
      app/build.gradle
  2. 13
      app/src/main/AndroidManifest.xml
  3. 14
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  4. 7
      app/src/main/java/net/pokeranalytics/android/model/realm/Bankroll.kt
  5. 4
      app/src/main/java/net/pokeranalytics/android/model/utils/SessionSetManager.kt
  6. 37
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  7. 61
      app/src/main/java/net/pokeranalytics/android/ui/activity/ImportActivity.kt
  8. 13
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ImportFragment.kt
  9. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt
  10. 42
      app/src/main/java/net/pokeranalytics/android/util/csv/CSVImporter.kt
  11. 2
      app/src/main/res/values-fr/strings.xml
  12. 1
      app/src/main/res/values/strings.xml

@ -72,7 +72,7 @@ dependencies {
// Android // Android
implementation 'androidx.appcompat:appcompat:1.0.2' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.core:core-ktx:1.1.0-alpha05' implementation 'androidx.core:core-ktx:1.2.0-alpha01'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
@ -88,13 +88,15 @@ dependencies {
implementation 'com.google.android.libraries.places:places:1.1.0' implementation 'com.google.android.libraries.places:places:1.1.0'
// Billing / Subscriptions // Billing / Subscriptions
// WARNING FOR 2.0: https://developer.android.com/google/play/billing/billing_library_releases_notes
// Purchases MUST BE ACKNOWLEDGED
implementation 'com.android.billingclient:billing:1.2.2' implementation 'com.android.billingclient:billing:1.2.2'
// Firebase // Firebase
implementation 'com.google.firebase:firebase-core:16.0.8' implementation 'com.google.firebase:firebase-core:16.0.9'
// Crashlytics // Crashlytics
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.9' implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
// Logs // Logs
implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.jakewharton.timber:timber:4.7.1'

@ -22,6 +22,7 @@
<activity <activity
android:name="net.pokeranalytics.android.ui.activity.HomeActivity" android:name="net.pokeranalytics.android.ui.activity.HomeActivity"
android:launchMode="singleInstance"
android:label="@string/app_name" android:label="@string/app_name"
android:screenOrientation="portrait"> android:screenOrientation="portrait">
<intent-filter> <intent-filter>
@ -30,11 +31,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity>
<activity
android:name="net.pokeranalytics.android.ui.activity.ImportActivity"
android:launchMode="singleTop">
<intent-filter tools:ignore="AppLinkUrlError"> <intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -49,6 +45,13 @@
</activity> </activity>
<activity
android:name="net.pokeranalytics.android.ui.activity.ImportActivity"
android:screenOrientation="portrait"
android:launchMode="singleTop">
</activity>
<activity <activity
android:name="net.pokeranalytics.android.ui.activity.SessionActivity" android:name="net.pokeranalytics.android.ui.activity.SessionActivity"
android:launchMode="singleTop" android:launchMode="singleTop"

@ -11,7 +11,9 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.pokeranalytics.android.model.migrations.Patcher import net.pokeranalytics.android.model.migrations.Patcher
import net.pokeranalytics.android.model.migrations.PokerAnalyticsMigration import net.pokeranalytics.android.model.migrations.PokerAnalyticsMigration
import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.model.utils.Seed import net.pokeranalytics.android.model.utils.Seed
import net.pokeranalytics.android.util.FakeDataManager import net.pokeranalytics.android.util.FakeDataManager
import net.pokeranalytics.android.util.PokerAnalyticsLogs import net.pokeranalytics.android.util.PokerAnalyticsLogs
@ -40,11 +42,13 @@ class PokerAnalyticsApplication : Application() {
.build() .build()
Realm.setDefaultConfiguration(realmConfiguration) Realm.setDefaultConfiguration(realmConfiguration)
// val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
// realm.executeTransaction { realm.executeTransaction {
// realm.where(Session::class.java).findAll().deleteAllFromRealm() realm.where(Session::class.java).findAll().deleteAllFromRealm()
// } realm.where(ComputableResult::class.java).findAll().deleteAllFromRealm()
// realm.close() realm.where(SessionSet::class.java).findAll().deleteAllFromRealm()
}
realm.close()
// Set up Crashlytics, disabled for debug builds // Set up Crashlytics, disabled for debug builds
val crashlyticsKit = Crashlytics.Builder() val crashlyticsKit = Crashlytics.Builder()

@ -101,12 +101,13 @@ open class Bankroll : RealmObject(), NameManageable, RowRepresentable {
fun getOrCreate(realm: Realm, name: String, live: Boolean = true, currencyCode: String? = null, currencyRate: Double? = null) : Bankroll { fun getOrCreate(realm: Realm, name: String, live: Boolean = true, currencyCode: String? = null, currencyRate: Double? = null) : Bankroll {
val bankroll = realm.where<Bankroll>().equalTo("name", name).findFirst() val br = realm.where<Bankroll>().equalTo("name", name).findFirst()
return if (bankroll != null) { return if (br != null) {
bankroll br
} else { } else {
val bankroll = Bankroll() val bankroll = Bankroll()
bankroll.name = name bankroll.name = name
bankroll.live = live
val currency = Currency() val currency = Currency()
currency.code = currencyCode currency.code = currencyCode
currency.rate = currencyRate currency.rate = currencyRate

@ -7,9 +7,7 @@ import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import kotlin.math.max import kotlin.math.max
class CorruptSessionSetException(message: String) : Exception(message) { class CorruptSessionSetException(message: String) : Exception(message)
}
/** /**
* The manager is in charge of updating the abstract concept of timeline, * The manager is in charge of updating the abstract concept of timeline,

@ -3,6 +3,7 @@ package net.pokeranalytics.android.ui.activity
import android.app.KeyguardManager import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView import com.google.android.material.bottomnavigation.BottomNavigationView
@ -13,7 +14,9 @@ import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Currency import net.pokeranalytics.android.model.realm.Currency
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.HomePagerAdapter import net.pokeranalytics.android.ui.adapter.HomePagerAdapter
import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.util.billing.AppGuard import net.pokeranalytics.android.util.billing.AppGuard
import timber.log.Timber
class HomeActivity : PokerAnalyticsActivity() { class HomeActivity : PokerAnalyticsActivity() {
@ -75,6 +78,30 @@ class HomeActivity : PokerAnalyticsActivity() {
} }
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.let {
when (intent.action) {
"android.intent.action.VIEW" -> { // import
val data = it.data
if (data != null) {
this.requestImportConfirmation(data)
} else {
throw IllegalStateException("URI null on import")
}
}
else -> {
Timber.d("Intent ${intent.action} unmanaged")
}
}
}
}
private fun observeRealmObjects() { private fun observeRealmObjects() {
val realm = getRealm() val realm = getRealm()
@ -125,4 +152,14 @@ class HomeActivity : PokerAnalyticsActivity() {
viewPager.setCurrentItem(index, false) viewPager.setCurrentItem(index, false)
} }
// Import
fun requestImportConfirmation(uri: Uri) {
showAlertDialog(this, R.string.import_confirmation, showCancelButton = true, positiveAction = {
ImportActivity.newInstance(this, uri)
})
}
} }

@ -1,12 +1,9 @@
package net.pokeranalytics.android.ui.activity package net.pokeranalytics.android.ui.activity
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.PersistableBundle
import androidx.core.app.ActivityCompat
import io.realm.Realm import io.realm.Realm
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
@ -15,8 +12,10 @@ import timber.log.Timber
class ImportActivity : PokerAnalyticsActivity() { class ImportActivity : PokerAnalyticsActivity() {
private lateinit var fileURI: Uri
enum class IntentKey(val keyName: String) { enum class IntentKey(val keyName: String) {
FILE_PATH("filepath") URI("uri")
} }
companion object { companion object {
@ -24,25 +23,24 @@ class ImportActivity : PokerAnalyticsActivity() {
/** /**
* Create a new instance for result * Create a new instance for result
*/ */
fun newInstance(context: Context, filePath: String) { fun newInstance(context: Context, uri: Uri) {
context.startActivity(getIntent(context, filePath)) context.startActivity(getIntent(context, uri))
} }
private fun getIntent(context: Context, filePath: String) : Intent { private fun getIntent(context: Context, uri: Uri) : Intent {
val intent = Intent(context, ImportActivity::class.java) val intent = Intent(context, ImportActivity::class.java)
intent.putExtra(ImportActivity.IntentKey.FILE_PATH.keyName, filePath) intent.putExtra(ImportActivity.IntentKey.URI.keyName, uri)
return intent return intent
} }
} }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) { this.fileURI = intent.getParcelableExtra(ImportActivity.IntentKey.URI.keyName)
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.activity_import) setContentView(R.layout.activity_import)
initUI() initUI()
} }
override fun onStop() { override fun onStop() {
@ -59,32 +57,27 @@ class ImportActivity : PokerAnalyticsActivity() {
val fragmentTransaction = supportFragmentManager.beginTransaction() val fragmentTransaction = supportFragmentManager.beginTransaction()
val fragment = ImportFragment() val fragment = ImportFragment()
val filePath = intent.getStringExtra(ImportActivity.IntentKey.FILE_PATH.keyName) val fis = contentResolver.openInputStream(fileURI)
fragment.setData(filePath) Timber.d("Load fragment data with: $fis")
fis?.let {
fragment.setData(it)
}
fragmentTransaction.add(R.id.container, fragment) fragmentTransaction.add(R.id.container, fragment)
fragmentTransaction.commit() fragmentTransaction.commit()
}
private fun requestPermission() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(
this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_REQUEST_ACCESS_FINE_LOCATION
)
}
} }
override fun onNewIntent(intent: Intent?) { // private fun requestPermission() {
super.onNewIntent(intent) // if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
// ActivityCompat.requestPermissions(
val f = intent?.data // this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), PERMISSION_REQUEST_ACCESS_FINE_LOCATION
val uri = f.toString() // )
Timber.d("!!!Intent!!! uri = $uri") // }
// }
} //
// override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { // super.onRequestPermissionsResult(requestCode, permissions, grantResults)
super.onRequestPermissionsResult(requestCode, permissions, grantResults) // }
}
} }

@ -12,6 +12,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 timber.log.Timber import timber.log.Timber
import java.io.InputStream
import java.util.* import java.util.*
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -21,11 +22,17 @@ class ImportFragment : RealmFragment() {
get() = Dispatchers.Main get() = Dispatchers.Main
private lateinit var filePath: String private lateinit var filePath: String
private lateinit var inputStream: InputStream
fun setData(path: String) { fun setData(path: String) {
this.filePath = path this.filePath = path
} }
fun setData(inputStream: InputStream) {
Timber.d("> setData with IS...")
this.inputStream = inputStream
}
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) super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_import, container, false) return inflater.inflate(R.layout.fragment_import, container, false)
@ -33,6 +40,8 @@ class ImportFragment : RealmFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
Timber.d("> onViewCreated...")
this.startImport() this.startImport()
} }
@ -42,9 +51,9 @@ class ImportFragment : RealmFragment() {
val test = GlobalScope.async { val test = GlobalScope.async {
val s = Date() val s = Date()
Timber.d(">>> start...") Timber.d(">>> Start Import...")
val csv = CSVImporter(filePath) val csv = CSVImporter(inputStream)
csv.start() csv.start()
val e = Date() val e = Date()

@ -95,7 +95,7 @@ open class DataManagerFragment : RealmFragment() {
this.getRealm().executeTransaction { this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item) val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) { if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id val uniqueIdentifier = managedItem.id
finishActivityWithResult(uniqueIdentifier) finishActivityWithResult(uniqueIdentifier)
} }
} }

@ -5,8 +5,24 @@ import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.CSVRecord import org.apache.commons.csv.CSVRecord
import timber.log.Timber import timber.log.Timber
import java.io.FileReader import java.io.FileReader
import java.io.InputStream
import java.io.InputStreamReader
import java.io.Reader
open class CSVImporter(var path: String) { open class CSVImporter {
private val COMMIT_FREQUENCY = 100
var path: String? = null
var inputStream: InputStream? = null
constructor(istream: InputStream) {
inputStream = istream
}
constructor(filePath: String) {
path = filePath
}
private var usedDescriptors: MutableList<CSVDescriptor> = mutableListOf() private var usedDescriptors: MutableList<CSVDescriptor> = mutableListOf()
private var currentDescriptor: CSVDescriptor? = null private var currentDescriptor: CSVDescriptor? = null
@ -15,13 +31,19 @@ open class CSVImporter(var path: String) {
val realm = Realm.getDefaultInstance() val realm = Realm.getDefaultInstance()
val reader = FileReader(this.path) var reader: Reader? = null
if (this.path != null) {
reader = FileReader(this.path)
}
if (this.inputStream != null) {
reader = InputStreamReader(this.inputStream)
}
val parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader) val parser = CSVFormat.DEFAULT.withAllowMissingColumnNames().parse(reader)
Timber.d("Starting import...") Timber.d("Starting import...")
realm.executeTransaction { realm.beginTransaction()
parser.forEachIndexed { index, record -> parser.forEachIndexed { index, record ->
@ -31,10 +53,17 @@ open class CSVImporter(var path: String) {
this.findDescriptor(record) this.findDescriptor(record)
} else { } else {
if ((index + 1) % COMMIT_FREQUENCY == 0) {
Timber.d("****** committing at ${index} sessions...")
realm.commitTransaction()
realm.beginTransaction()
}
currentDescriptor?.let { currentDescriptor?.let {
if (record.size() == 0) { if (record.size() == 0) {
this.usedDescriptors.add(it) this.usedDescriptors.add(it)
this.currentDescriptor = null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file) this.currentDescriptor =
null // reset descriptor when encountering an empty line (multiple descriptors can be found in a single file)
} else { } else {
it.parse(realm, record) it.parse(realm, record)
} }
@ -44,11 +73,10 @@ open class CSVImporter(var path: String) {
} }
} }
}
Timber.d("Ending import...") realm.commitTransaction()
// this.save(realm) Timber.d("Ending import...")
realm.close() realm.close()
} }

@ -379,7 +379,7 @@
<string name="operation_empty_field_error">Vérifiez que la transaction possède un type et un montant</string> <string name="operation_empty_field_error">Vérifiez que la transaction possède un type et un montant</string>
<string name="operation_type_empty_field_error">Il faut choisir un nom!</string> <string name="operation_type_empty_field_error">Il faut choisir un nom!</string>
<string name="operation_types">Types de transactions</string> <string name="operation_types">Types de transactions</string>
<string name="operations">Transaction</string> <string name="operations">Transactions</string>
<string name="other">Autres</string> <string name="other">Autres</string>
<string name="password_explanation">Choisissez un code PIN pour\n protéger l\'accès à l\'application.\nUn code PIN ne peut pas être retrouvé.\nSoyez attentif lors de l\'activation\n de cette fonction.</string> <string name="password_explanation">Choisissez un code PIN pour\n protéger l\'accès à l\'application.\nUn code PIN ne peut pas être retrouvé.\nSoyez attentif lors de l\'activation\n de cette fonction.</string>
<string name="password_protection">Code PIN</string> <string name="password_protection">Code PIN</string>

@ -31,6 +31,7 @@
<string name="launch_report">Launch Report</string> <string name="launch_report">Launch Report</string>
<string name="progress">Progress</string> <string name="progress">Progress</string>
<string name="save_report">Save Report</string> <string name="save_report">Save Report</string>
<string name="import_confirmation">Do you want to proceed with the file import?</string>
<string name="update_entity" formatted="false">Update %s</string> <string name="update_entity" formatted="false">Update %s</string>
<string name="comparison_chart">Comparison chart</string> <string name="comparison_chart">Comparison chart</string>
<string name="filter_currently_selected">The filter cannot be deleted because it is currently selected.</string> <string name="filter_currently_selected">The filter cannot be deleted because it is currently selected.</string>

Loading…
Cancel
Save