Adds ability to save & delete custom reports

dev
Laurent 7 years ago
parent 1a4535ae59
commit f290b21a31
  1. 40
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 5
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  3. 20
      app/src/main/java/net/pokeranalytics/android/model/realm/ReportSetup.kt
  4. 45
      app/src/main/java/net/pokeranalytics/android/ui/activity/ComparisonReportActivity.kt
  5. 11
      app/src/main/java/net/pokeranalytics/android/ui/activity/ProgressReportActivity.kt
  6. 52
      app/src/main/java/net/pokeranalytics/android/ui/activity/TableReportActivity.kt
  7. 38
      app/src/main/java/net/pokeranalytics/android/ui/activity/components/ReportActivity.kt
  8. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollFragment.kt
  9. 9
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  10. 31
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportsFragment.kt
  11. 10
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/DeletableItemFragment.kt
  12. 4
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/BankrollDataFragment.kt
  13. 154
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/DataManagerFragment.kt
  14. 176
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt
  15. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/LocationDataFragment.kt
  16. 100
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/AbstractReportFragment.kt
  17. 8
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ComparisonReportFragment.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/ProgressReportFragment.kt
  19. 5
      app/src/main/java/net/pokeranalytics/android/ui/fragment/report/TableReportFragment.kt
  20. 21
      app/src/main/res/layout/dialog_edit_text.xml
  21. 2
      app/src/main/res/layout/fragment_bankroll.xml
  22. 2
      app/src/main/res/layout/fragment_data_list.xml
  23. 2
      app/src/main/res/layout/fragment_reports.xml
  24. 1
      app/src/main/res/values/strings.xml
  25. 2
      build.gradle

@ -11,7 +11,6 @@ import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.filter import net.pokeranalytics.android.model.filter.filter
import net.pokeranalytics.android.model.realm.ComputableResult import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.model.realm.Filter import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.model.realm.SessionSet import net.pokeranalytics.android.model.realm.SessionSet
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.util.extensions.startOfDay import net.pokeranalytics.android.util.extensions.startOfDay
@ -35,7 +34,8 @@ class Calculator {
query: Query = Query(), query: Query = Query(),
filter: Filter? = null, filter: Filter? = null,
var aggregationType: AggregationType? = null, var aggregationType: AggregationType? = null,
var userGenerated: Boolean = false var userGenerated: Boolean = false,
var reportSetupId: String? = null
) { ) {
var evolutionValues: EvolutionValues = evolutionValues var evolutionValues: EvolutionValues = evolutionValues
@ -47,17 +47,17 @@ class Calculator {
} }
private var _query: Query = query private var _query: Query = query
private var _filter: Filter? = filter var filter: Filter? = filter
init { init {
if (!this._query.conditions.isEmpty() && this._filter != null) { if (!this._query.conditions.isEmpty() && this.filter != null) {
throw IllegalStateException("Can't specify a query with conditions AND a filter") throw IllegalStateException("Can't specify a query with conditions AND a filter")
} }
} }
val query: Query val query: Query
get() { get() {
this._filter?.let { this.filter?.let {
return it.query return it.query
} }
return this._query return this._query
@ -134,21 +134,21 @@ class Calculator {
} }
} }
fun reportSetup(name: String): ReportSetup { // fun reportSetup(name: String): ReportSetup {
//
val rs = ReportSetup() // val rs = ReportSetup()
rs.name = name // rs.name = name
rs.display = this.display.ordinal // rs.display = this.display.ordinal
this.stats.forEach { // this.stats.forEach {
rs.statIds.add(it.uniqueIdentifier) // rs.statIds.add(it.uniqueIdentifier)
} // }
this.criterias.forEach { // this.criterias.forEach {
rs.criteriaIds.add(it.uniqueIdentifier) // rs.criteriaIds.add(it.uniqueIdentifier)
} // }
rs.filter = this._filter // rs.filter = this.filter
//
return rs // return rs
} // }
/** /**
* Returns some default name * Returns some default name

@ -24,7 +24,8 @@ enum class LiveData : Localizable {
TRANSACTION, TRANSACTION,
TRANSACTION_TYPE, TRANSACTION_TYPE,
FILTER, FILTER,
CUSTOM_FIELD; CUSTOM_FIELD,
REPORT_SETUP;
fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> { fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> {
val results = realm.where(this.relatedEntity).findAll().sort(fieldName ?: this.sortingFieldName, sortOrder ?: this.sorting) val results = realm.where(this.relatedEntity).findAll().sort(fieldName ?: this.sortingFieldName, sortOrder ?: this.sorting)
@ -105,6 +106,7 @@ enum class LiveData : Localizable {
TRANSACTION_TYPE -> TransactionType::class.java TRANSACTION_TYPE -> TransactionType::class.java
FILTER -> Filter::class.java FILTER -> Filter::class.java
CUSTOM_FIELD -> CustomField::class.java CUSTOM_FIELD -> CustomField::class.java
REPORT_SETUP -> ReportSetup::class.java
} }
} }
@ -148,6 +150,7 @@ enum class LiveData : Localizable {
TRANSACTION_TYPE -> R.string.operation_types TRANSACTION_TYPE -> R.string.operation_types
FILTER -> R.string.filter FILTER -> R.string.filter
CUSTOM_FIELD -> R.string.custom_fields CUSTOM_FIELD -> R.string.custom_fields
REPORT_SETUP -> R.string.custom
} }
} }

@ -1,6 +1,7 @@
package net.pokeranalytics.android.model.realm package net.pokeranalytics.android.model.realm
import android.content.Context import android.content.Context
import io.realm.Realm
import io.realm.RealmList import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
@ -8,15 +9,17 @@ import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
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
import java.util.* import java.util.*
open class ReportSetup : RealmObject(), RowRepresentable { open class ReportSetup : RealmObject(), RowRepresentable, Deletable {
@PrimaryKey @PrimaryKey
var id = UUID.randomUUID().toString() override var id = UUID.randomUUID().toString()
// The name of the report // The name of the report
var name: String = "" var name: String = ""
@ -60,8 +63,19 @@ open class ReportSetup : RealmObject(), RowRepresentable {
stats = stats, stats = stats,
criterias = criteria, criterias = criteria,
filter = this.filter, filter = this.filter,
userGenerated = true userGenerated = true,
reportSetupId = this.id
) )
} }
// Deletable
override fun isValidForDelete(realm: Realm): Boolean {
return true
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
} }

@ -1,35 +1,32 @@
package net.pokeranalytics.android.ui.activity package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.report.ComparisonReportFragment import net.pokeranalytics.android.ui.fragment.report.ComparisonReportFragment
class ComparisonReportActivity : PokerAnalyticsActivity() { class ComparisonReportActivity : ReportActivity() {
companion object { // companion object {
//
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects // // Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
private var report: Report? = null // private var report: Report? = null
private var reportTitle: String = "" // private var reportTitle: String = ""
//
/** // /**
* Default constructor // * Default constructor
*/ // */
fun newInstance(context: Context, report: Report, reportTitle: String) { // fun newInstance(context: Context, report: Report, reportTitle: String) {
//parameters = GraphParameters(stat, group, report) // //parameters = GraphParameters(stat, group, report)
this.report = report // this.report = report
this.reportTitle = reportTitle // this.reportTitle = reportTitle
val intent = Intent(context, ComparisonReportActivity::class.java) // val intent = Intent(context, ComparisonReportActivity::class.java)
context.startActivity(intent) // context.startActivity(intent)
} // }
//
} // }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

@ -3,10 +3,12 @@ package net.pokeranalytics.android.ui.activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.fragment.report.ProgressReportFragment import net.pokeranalytics.android.ui.fragment.report.ProgressReportFragment
@ -24,12 +26,19 @@ class ProgressReportActivity : PokerAnalyticsActivity() {
* Default constructor * Default constructor
*/ */
fun newInstance(context: Context, stat: Stat, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) { fun newInstance(context: Context, stat: Stat, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) {
parameters = StatisticsDetailsParameters(stat, report, title) this.parameters = StatisticsDetailsParameters(stat, report, title)
this.displayAggregationChoices = displayAggregationChoices this.displayAggregationChoices = displayAggregationChoices
val intent = Intent(context, ProgressReportActivity::class.java) val intent = Intent(context, ProgressReportActivity::class.java)
context.startActivity(intent) context.startActivity(intent)
} }
fun newInstanceForResult(fragment: Fragment, stat: Stat, report: Report, displayAggregationChoices: Boolean = true, title: String? = null) {
this.parameters = StatisticsDetailsParameters(stat, report, title)
this.displayAggregationChoices = displayAggregationChoices
val intent = Intent(fragment.context, ProgressReportActivity::class.java)
fragment.startActivityForResult(intent, ReportActivity.DEFAULT_REQUEST_CODE)
}
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

@ -1,32 +1,38 @@
package net.pokeranalytics.android.ui.activity package net.pokeranalytics.android.ui.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.report.TableReportFragment import net.pokeranalytics.android.ui.fragment.report.TableReportFragment
class TableReportActivity : PokerAnalyticsActivity() { class TableReportActivity : ReportActivity() {
companion object { // companion object {
// const val DEFAULT_REQUEST_CODE = 1000
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects //
private var report: Report? = null // // Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
private var reportTitle: String = "" // private var report: Report? = null
// private var reportTitle: String = ""
/** //
* Default constructor // /**
*/ // * Default constructor
fun newInstance(context: Context, report: Report, reportTitle: String) { // */
this.report = report // fun newInstance(context: Context, report: Report, reportTitle: String) {
this.reportTitle = reportTitle // this.report = report
val intent = Intent(context, TableReportActivity::class.java) // this.reportTitle = reportTitle
context.startActivity(intent) // val intent = Intent(context, TableReportActivity::class.java)
} // context.startActivity(intent)
// }
} //
// fun newInstanceForResult(fragment: Fragment, report: Report, reportTitle: String) {
// this.report = report
// this.reportTitle = reportTitle
//
// val intent = Intent(fragment.requireContext(), TableReportActivity::class.java)
// fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE)
// }
//
// }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

@ -0,0 +1,38 @@
package net.pokeranalytics.android.ui.activity.components
import android.content.Context
import android.content.Intent
import androidx.fragment.app.Fragment
import net.pokeranalytics.android.calculus.Report
abstract class ReportActivity : PokerAnalyticsActivity() {
companion object {
const val DEFAULT_REQUEST_CODE = 999
// Unparcel fails when setting a custom Parcelable object on Entry so we use a static reference to passe objects
var report: Report? = null
var reportTitle: String = ""
/**
* Default constructor
*/
fun newInstance(context: Context, report: Report, reportTitle: String) {
this.report = report
this.reportTitle = reportTitle
val intent = Intent(context, this::class.java)
context.startActivity(intent)
}
fun newInstanceForResult(fragment: Fragment, clazz: Class<*>, report: Report, reportTitle: String) {
this.report = report
this.reportTitle = reportTitle
val intent = Intent(fragment.requireContext(), clazz)
fragment.startActivityForResult(intent, DEFAULT_REQUEST_CODE)
}
}
}

@ -85,13 +85,14 @@ class BankrollFragment : DeletableItemFragment(), StaticRowRepresentableDataSour
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) {
val needToDeleteItem = data?.getBooleanExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, false) ?: false val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
if (needToDeleteItem) { itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
delay(300) delay(300)
deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), lastItemClickedId) deleteItem(bankrollAdapter, LiveData.BANKROLL.items(getRealm()), id)
} }
} }
} else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) { } else if (requestCode == REQUEST_CODE_CREATE && resultCode == Activity.RESULT_OK) {
//TODO: Refresh bankrolls //TODO: Refresh bankrolls
initData() initData()

@ -108,14 +108,15 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) {
val needToDeleteItem =
data?.getBooleanExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, false) ?: false val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
if (needToDeleteItem) { itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) { GlobalScope.launch(Dispatchers.Main) {
delay(300) delay(300)
deleteItem(dataListAdapter, items, lastItemClickedId) deleteItem(dataListAdapter, LiveData.BANKROLL.items(getRealm()), id)
} }
} }
} }
} }

@ -13,21 +13,21 @@ import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_data_list.* import kotlinx.android.synthetic.main.fragment_data_list.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.Stat import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.combined import net.pokeranalytics.android.model.combined
import net.pokeranalytics.android.model.realm.ReportSetup import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.ui.activity.ComparisonReportActivity import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.ProgressReportActivity import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.activity.ReportCreationActivity
import net.pokeranalytics.android.ui.activity.TableReportActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.components.DeletableItemFragment
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
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
@ -35,7 +35,7 @@ import net.pokeranalytics.android.ui.view.rowrepresentable.ReportRow
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate { class ReportsFragment : DeletableItemFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {
private lateinit var reportsAdapter: RowRepresentableAdapter private lateinit var reportsAdapter: RowRepresentableAdapter
private lateinit var reportSetups: RealmResults<ReportSetup> private lateinit var reportSetups: RealmResults<ReportSetup>
@ -77,9 +77,17 @@ class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRe
this.launchReportWithOptions(options, options.getName(requireContext())) this.launchReportWithOptions(options, options.getName(requireContext()))
} }
ReportCreationActivity.options = null ReportCreationActivity.options = null
} else if (requestCode == ReportActivity.DEFAULT_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
itemToDeleteId?.let { id ->
GlobalScope.launch(Dispatchers.Main) {
delay(300)
deleteItem(reportsAdapter, LiveData.REPORT_SETUP.items(getRealm()), id)
}
}
} }
}
}
// Business // Business
@ -188,13 +196,16 @@ class ReportsFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRe
when (options.display) { when (options.display) {
Calculator.Options.Display.TABLE -> { Calculator.Options.Display.TABLE -> {
TableReportActivity.newInstance(requireContext(), report, reportName) ReportActivity.newInstanceForResult(this@ReportsFragment, TableReportActivity::class.java, report, reportName)
// TableReportActivity.newInstanceForResult(this@ReportsFragment, report, reportName)
// TableReportActivity.newInstance(requireContext(), report, reportName)
} }
Calculator.Options.Display.PROGRESS -> { Calculator.Options.Display.PROGRESS -> {
ProgressReportActivity.newInstance(requireContext(), options.stats.first(), report) ProgressReportActivity.newInstanceForResult(this@ReportsFragment, options.stats.first(), report)
} }
Calculator.Options.Display.COMPARISON -> { Calculator.Options.Display.COMPARISON -> {
ComparisonReportActivity.newInstance(requireContext(), report, reportName) // ComparisonReportActivity.newInstance(requireContext(), report, reportName)
ReportActivity.newInstanceForResult(this@ReportsFragment, ComparisonReportActivity::class.java, report, reportName)
} }
else -> { else -> {
Timber.d("Report type not handled at the moment") Timber.d("Report type not handled at the moment")

@ -2,8 +2,8 @@ package net.pokeranalytics.android.ui.fragment.components
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import io.realm.RealmObject import io.realm.RealmObject
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
@ -20,12 +20,12 @@ open class DeletableItemFragment : RealmFragment() {
private var deletedItem: RealmObject? = null private var deletedItem: RealmObject? = null
private var lastDeletedItemPosition: Int = 0 private var lastDeletedItemPosition: Int = 0
private var dataListAdapter: RowRepresentableAdapter? = null private var dataListAdapter: RowRepresentableAdapter? = null
private var coordinatorLayout: CoordinatorLayout? = null private var mainLayout: ViewGroup? = null
private var snackBar: Snackbar? = null private var snackBar: Snackbar? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
this.coordinatorLayout = view.findViewById(R.id.coordinatorLayout) this.mainLayout = view.findViewById(R.id.mainLayout)
} }
override fun onPause() { override fun onPause() {
@ -82,7 +82,7 @@ open class DeletableItemFragment : RealmFragment() {
*/ */
private fun showUndoSnackBar() { private fun showUndoSnackBar() {
val message = String.format(getString(R.string.data_deleted)) val message = String.format(getString(R.string.data_deleted))
this.coordinatorLayout?.let { view -> this.mainLayout?.let { view ->
snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE) snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
snackBar?.setAction(R.string.cancel) { snackBar?.setAction(R.string.cancel) {
getRealm().executeTransaction { realm -> getRealm().executeTransaction { realm ->
@ -93,6 +93,8 @@ open class DeletableItemFragment : RealmFragment() {
} }
} }
snackBar?.show() snackBar?.show()
} ?: run {
throw IllegalStateException("mainLayout is not defined")
} }
} }

@ -157,11 +157,11 @@ class BankrollDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
/** /**
* Init data * Init data
*/ */
private fun initData() { override fun initData() {
defaultCurrency = UserDefaults.currency defaultCurrency = UserDefaults.currency
if (!isUpdating) { if (!deleteButtonShouldAppear) {
bankroll.currency = net.pokeranalytics.android.model.realm.Currency() bankroll.currency = net.pokeranalytics.android.model.realm.Currency()
bankroll.currency?.code = defaultCurrency.currencyCode bankroll.currency?.code = defaultCurrency.currencyCode
bankroll.currency?.rate = 1.0 bankroll.currency?.rate = 1.0

@ -0,0 +1,154 @@
package net.pokeranalytics.android.ui.fragment.data
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.AlertDialog
import io.realm.RealmObject
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
open class DataManagerFragment : RealmFragment() {
lateinit var item: RealmObject
lateinit var liveDataType: LiveData
protected var primaryKey: String? = null
var deleteButtonShouldAppear = false
set(value) {
field = value
this.updateMenuUI()
}
var saveButtonShouldAppear = true
set(value) {
field = value
this.updateMenuUI()
}
protected var dataType: Int? = null
private var editableMenu: Menu? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
/**
* Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.delete)?.isVisible = this.deleteButtonShouldAppear
editableMenu?.findItem(R.id.save)?.isVisible = this.saveButtonShouldAppear
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when (item!!.itemId) {
R.id.save -> saveData()
R.id.delete -> deleteData()
}
return true
}
/**
* Init data
*/
protected open fun initData() {
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
}
/**
* Save data
*/
protected open fun saveData() {
val savable = this.item
when (savable) {
is Savable -> {
val status = savable.getSaveValidityStatus(realm = this.getRealm())
when (status) {
SaveValidityStatus.VALID -> {
this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
}
}
else -> {
val message = savable.getFailedSaveMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
} else -> {
throw ConfigurationException("Save action called on un-Savable object")
}
}
}
/**
* Delete data
*/
protected open fun deleteData() {
val deletable = this.item as Deletable
val realm = this.getRealm()
if (deletable.isValidForDelete(realm)) {
val intent = Intent()
intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, deletable.id)
activity?.setResult(Activity.RESULT_OK, intent)
activity?.finish()
} else {
val status = deletable.getDeleteStatus(realm)
val message = deletable.getFailedDeleteMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(Activity.RESULT_OK, intent)
activity?.finish()
}
}

@ -1,44 +1,29 @@
package net.pokeranalytics.android.ui.fragment.data package net.pokeranalytics.android.ui.fragment.data
import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_editable_data.* import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_editable_data.view.* import kotlinx.android.synthetic.main.fragment_editable_data.view.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Editable import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable import net.pokeranalytics.android.ui.view.RowRepresentable
open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate { open class EditableDataFragment : DataManagerFragment(), RowRepresentableDelegate {
lateinit var parentActivity: PokerAnalyticsActivity lateinit var parentActivity: PokerAnalyticsActivity
lateinit var item: RealmObject
lateinit var liveDataType: LiveData
lateinit var rowRepresentableAdapter: RowRepresentableAdapter lateinit var rowRepresentableAdapter: RowRepresentableAdapter
private var editableMenu: Menu? = null
private var dataType: Int? = null
private var primaryKey: String? = null
var isUpdating = false
var shouldOpenKeyboard = true var shouldOpenKeyboard = true
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
@ -49,24 +34,15 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
initUI() initUI()
initData()
}
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
menu?.clear()
inflater?.inflate(R.menu.toolbar_editable_data, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
} }
/**
override fun onOptionsItemSelected(item: MenuItem?): Boolean { * Set fragment data
when (item!!.itemId) { */
R.id.save -> saveData() fun setData(dataType: Int, primaryKey: String?) {
R.id.delete -> deleteData() this.dataType = dataType
} this.liveDataType = LiveData.values()[dataType]
return true this.primaryKey = primaryKey
} }
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) { override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
@ -90,6 +66,16 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true) parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true) setHasOptionsMenu(true)
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
proxyItem?.let {
//TODO: Localize
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(requireContext()).toLowerCase().capitalize()}"
deleteButtonShouldAppear = true
} ?: run {
//TODO: Localize
this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
}
val viewManager = LinearLayoutManager(requireContext()) val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply { recyclerView.apply {
@ -105,121 +91,21 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
return this.item as RowRepresentableDataSource return this.item as RowRepresentableDataSource
} }
/** override fun initData() {
* Init data super.initData()
*/
private fun initData() {
if (this.dataType != null) {
val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
proxyItem?.let {
//TODO: Localize
this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}"
isUpdating = true
} ?: run {
//TODO: Localize
this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
}
this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)
val dataSource = getDataSource()
this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this)
this.recyclerView.adapter = rowRepresentableAdapter
// When creating an object, open automatically the keyboard for the first row
if (!isUpdating && shouldOpenKeyboard) {
val row = dataSource.adapterRows()?.firstOrNull()
row?.let {
onRowSelected(0, it)
}
}
}
}
/** val dataSource = getDataSource()
* Update menu UI this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this)
*/ this.recyclerView.adapter = rowRepresentableAdapter
private fun updateMenuUI() {
editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating
editableMenu?.findItem(R.id.save)?.isVisible = true
}
/** // When creating an object, open automatically the keyboard for the first row
* Save data if (!deleteButtonShouldAppear && shouldOpenKeyboard) {
*/ val row = dataSource.adapterRows()?.firstOrNull()
fun saveData() { row?.let {
onRowSelected(0, it)
val savable = this.item
when (savable) {
is Savable -> {
val status = savable.getSaveValidityStatus(realm = this.getRealm())
when (status) {
SaveValidityStatus.VALID -> {
this.getRealm().executeTransaction {
val managedItem = it.copyToRealmOrUpdate(this.item)
if (managedItem is Savable) {
val uniqueIdentifier = (managedItem as Savable).id
finishActivityWithResult(uniqueIdentifier)
}
}
}
else -> {
val message = savable.getFailedSaveMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
} else -> {
throw ConfigurationException("Save action called on un-Savable object")
} }
} }
} }
/**
* Delete data
*/
private fun deleteData() {
val deletable = this.item as Deletable
val realm = this.getRealm()
if (deletable.isValidForDelete(realm)) {
val intent = Intent()
intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, true)
activity?.setResult(RESULT_OK, intent)
activity?.finish()
} else {
val status = deletable.getDeleteStatus(realm)
val message = deletable.getFailedDeleteMessage(status)
val builder = AlertDialog.Builder(requireContext())
.setMessage(message)
.setNegativeButton(R.string.ok, null)
builder.show()
}
}
/**
* Finish the activity with a result
*/
private fun finishActivityWithResult(uniqueIdentifier: String) {
val intent = Intent()
intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
activity?.setResult(RESULT_OK, intent)
activity?.finish()
}
/**
* Set fragment data
*/
fun setData(dataType: Int, primaryKey: String?) {
this.dataType = dataType
this.liveDataType = LiveData.values()[dataType]
this.primaryKey = primaryKey
}
} }

@ -40,7 +40,7 @@ class LocationDataFragment : EditableDataFragment(), StaticRowRepresentableDataS
shouldOpenKeyboard = false shouldOpenKeyboard = false
locationActivated = parentActivity.hasLocationPermissionGranted() locationActivated = parentActivity.hasLocationPermissionGranted()
if (isUpdating) { if (deleteButtonShouldAppear) {
// If we update a location, we set the switch to the correct value // If we update a location, we set the switch to the correct value
locationActivated = location.latitude != null && location.longitude != null locationActivated = location.latitude != null && location.longitude != null

@ -1,37 +1,41 @@
package net.pokeranalytics.android.ui.fragment.report package net.pokeranalytics.android.ui.fragment.report
import android.os.Bundle import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import kotlinx.android.synthetic.main.fragment_progress_report.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Report import net.pokeranalytics.android.calculus.Report
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.ReportSetup
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.fragment.components.RealmFragment import net.pokeranalytics.android.ui.fragment.data.DataManagerFragment
abstract class AbstractReportFragment : RealmFragment() { abstract class AbstractReportFragment : DataManagerFragment() {
protected lateinit var selectedReport: Report private lateinit var _selectedReport: Report
val selectedReport: Report
get() {
return this._selectedReport
}
fun setReport(report: Report) {
this._selectedReport = report
this.primaryKey = report.options.reportSetupId
}
protected var reportTitle: String? = null protected var reportTitle: String? = null
private var editableMenu: Menu? = null
protected lateinit var parentActivity: PokerAnalyticsActivity protected lateinit var parentActivity: PokerAnalyticsActivity
override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { override fun onCreate(savedInstanceState: Bundle?) {
menu?.clear() super.onCreate(savedInstanceState)
inflater?.inflate(R.menu.toolbar_report, menu)
this.editableMenu = menu
updateMenuUI()
super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean { this.liveDataType = LiveData.REPORT_SETUP
when (item!!.itemId) { this.saveButtonShouldAppear = this._selectedReport.options.userGenerated
R.id.save -> this.saveReportRequest() this.deleteButtonShouldAppear = (this.primaryKey != null)
}
return true
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@ -39,25 +43,57 @@ abstract class AbstractReportFragment : RealmFragment() {
parentActivity = activity as PokerAnalyticsActivity parentActivity = activity as PokerAnalyticsActivity
} }
/** override fun saveData() {
* Update menu UI
*/
private fun updateMenuUI() {
editableMenu?.findItem(R.id.save)?.let {
it.isVisible = this.selectedReport.options.userGenerated
it.icon.setTint(requireContext().getColor(R.color.white))
}
}
private fun saveReportRequest() { activity?.let {
val builder = AlertDialog.Builder(it)
// Get the layout inflater
val inflater = requireActivity().layoutInflater;
// Inflate and set the layout for the dialog
// Pass null as the parent view because its going in the dialog layout
val view = inflater.inflate(R.layout.dialog_edit_text, null)
val nameEditText = view.findViewById<EditText>(R.id.reportName)
builder.setView(view)
// Add action buttons
.setPositiveButton(R.string.save) { dialog, id ->
saveReport(nameEditText.text.toString())
dialog.dismiss()
}
.setNegativeButton(R.string.cancel) { dialog, id ->
dialog.cancel()
}
val dialog = builder.create()
dialog.show()
} ?: throw IllegalStateException("Activity cannot be null")
} }
private fun saveReport(name: String) { private fun saveReport(name: String) {
getRealm().executeTransaction { getRealm().executeTransaction { realm ->
val report = this.selectedReport.options.reportSetup(name)
it.insert(report) val rs = this.item as ReportSetup
val options = this._selectedReport.options
rs.name = name
rs.display = options.display.ordinal
options.stats.forEach {
rs.statIds.add(it.uniqueIdentifier)
}
options.criterias.forEach {
rs.criteriaIds.add(it.uniqueIdentifier)
}
rs.filter = options.filter
this.item = rs
this.deleteButtonShouldAppear = true
toolbar.title = name
realm.copyToRealmOrUpdate(rs)
} }
} }
} }

@ -18,7 +18,7 @@ class ComparisonReportFragment : AbstractReportFragment() {
val fragment = ComparisonReportFragment() val fragment = ComparisonReportFragment()
fragment.reportTitle = reportTitle fragment.reportTitle = reportTitle
report?.let { report?.let {
fragment.selectedReport = it fragment.setReport(it)
} }
val bundle = Bundle() val bundle = Bundle()
fragment.arguments = bundle fragment.arguments = bundle
@ -27,15 +27,11 @@ class ComparisonReportFragment : AbstractReportFragment() {
} }
} }
// private var reports: MutableMap<AggregationType, Report> = hashMapOf()
// private var stat: Stat = Stat.NET_RESULT
// private var displayAggregationChoices: Boolean = true
/** /**
* Set data * Set data
*/ */
fun setData(report: Report) { fun setData(report: Report) {
this.selectedReport = report this.setReport(report)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

@ -66,7 +66,7 @@ class ProgressReportFragment : AbstractReportFragment() {
*/ */
fun setData(stat: Stat, report: Report, displayAggregationChoices: Boolean, title: String? = null) { fun setData(stat: Stat, report: Report, displayAggregationChoices: Boolean, title: String? = null) {
this.stat = stat this.stat = stat
this.selectedReport = report this.setReport(report)
this.displayAggregationChoices = displayAggregationChoices this.displayAggregationChoices = displayAggregationChoices
this.reportTitle = title this.reportTitle = title

@ -14,14 +14,11 @@ class TableReportFragment : AbstractReportFragment() {
companion object { companion object {
/**
* Create new instance
*/
fun newInstance(report: Report? = null, title: String? = null): TableReportFragment { fun newInstance(report: Report? = null, title: String? = null): TableReportFragment {
val fragment = TableReportFragment() val fragment = TableReportFragment()
fragment.reportTitle = title fragment.reportTitle = title
report?.let { report?.let {
fragment.selectedReport = it fragment.setReport(it)
} }
val bundle = Bundle() val bundle = Bundle()
fragment.arguments = bundle fragment.arguments = bundle

@ -0,0 +1,21 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="24dp">
<androidx.appcompat.widget.AppCompatTextView
android:text="@string/save_report"
style="@style/PokerAnalyticsTheme.TextView.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/reportName"
style="@style/PokerAnalyticsTheme.EditText"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:hint="@string/name" />
</LinearLayout>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinatorLayout" android:id="@+id/mainLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

@ -2,7 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout" android:id="@+id/mainLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

@ -2,7 +2,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/mainLayout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">

@ -30,6 +30,7 @@
<string name="new_report_step_filter">Select a filter or launch report</string> <string name="new_report_step_filter">Select a filter or launch report</string>
<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="address">Address</string> <string name="address">Address</string>
<string name="suggestions">Naming suggestions</string> <string name="suggestions">Naming suggestions</string>

@ -10,7 +10,7 @@ buildscript {
} }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.4.0' classpath 'com.android.tools.build:gradle:3.4.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'io.realm:realm-gradle-plugin:5.8.0' classpath 'io.realm:realm-gradle-plugin:5.8.0'
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.2.0'

Loading…
Cancel
Save