Custom report creation (until launch)

dev
Laurent 7 years ago
parent 932276f32a
commit 9b95be33a7
  1. 42
      app/src/main/java/net/pokeranalytics/android/calculus/Calculator.kt
  2. 14
      app/src/main/java/net/pokeranalytics/android/calculus/Stat.kt
  3. 26
      app/src/main/java/net/pokeranalytics/android/model/Criteria.kt
  4. 2
      app/src/main/java/net/pokeranalytics/android/model/LiveData.kt
  5. 2
      app/src/main/java/net/pokeranalytics/android/model/realm/Session.kt
  6. 6
      app/src/main/java/net/pokeranalytics/android/ui/activity/HomeActivity.kt
  7. 2
      app/src/main/java/net/pokeranalytics/android/ui/adapter/RowRepresentableAdapter.kt
  8. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/BankrollDetailsFragment.kt
  9. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarDetailsFragment.kt
  10. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CurrenciesFragment.kt
  11. 106
      app/src/main/java/net/pokeranalytics/android/ui/fragment/DataListFragment.kt
  12. 235
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportCreationFragment.kt
  13. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/ReportDetailsFragment.kt
  14. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/SessionFragment.kt
  15. 2
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticDetailsFragment.kt
  16. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/LegendView.kt
  17. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/RowRepresentable.kt
  18. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  19. 2
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomizableRowRepresentable.kt
  20. 27
      app/src/main/res/layout/fragment_report_creation.xml
  21. 6
      app/src/main/res/menu/navigation_home.xml
  22. 2
      app/src/main/res/values/strings.xml

@ -1,6 +1,7 @@
package net.pokeranalytics.android.calculus
import io.realm.Realm
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Stat.*
import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.combined
@ -8,8 +9,10 @@ import net.pokeranalytics.android.model.extensions.hourlyDuration
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.filter
import net.pokeranalytics.android.model.realm.ComputableResult
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.ui.view.RowRepresentable
import net.pokeranalytics.android.util.extensions.startOfDay
import timber.log.Timber
import java.util.*
@ -29,19 +32,50 @@ class Calculator {
var evolutionValues: EvolutionValues = EvolutionValues.NONE,
var stats: List<Stat> = listOf(),
var criterias: List<Criteria> = listOf(),
var query: Query = Query(),
var aggregationType: AggregationType? = null
query: Query = Query(),
filter: Filter? = null,
var aggregationType: AggregationType? = null,
var userGenerated: Boolean = false
) {
private var _query: Query = query
private var _filter: Filter? = filter
init {
if (!this._query.conditions.isEmpty() && this._filter != null) {
throw IllegalStateException("Can't specify a query with conditions AND a filter")
}
}
val query: Query
get() {
this._filter?.let {
return it.query
}
return this._query
}
/**
* The way the stats are going to be displayed
*/
enum class Display {
enum class Display : RowRepresentable {
TABLE,
EVOLUTION,
COMPARISON,
MAP,
POLYNOMIAL
POLYNOMIAL;
override val resId: Int?
get() {
return when (this) {
TABLE -> R.string.table
EVOLUTION -> R.string.curve
COMPARISON -> R.string.comparison
MAP -> R.string.map
POLYNOMIAL -> null
}
}
}
/**

@ -58,6 +58,11 @@ enum class Stat : RowRepresentable {
companion object {
val userSelectableList: List<Stat>
get() {
return values().filter { it.canBeUserSelected }
}
fun returnOnInvestment(netResult: Double, buyin: Double): Double? {
if (buyin == 0.0) {
return null
@ -114,6 +119,7 @@ enum class Stat : RowRepresentable {
MINIMUM_NETRESULT -> R.string.min_net_result
MAXIMUM_DURATION -> R.string.longest_session
DAYS_PLAYED -> R.string.days_played
TOTAL_BUYIN -> R.string.total_buyin
else -> throw IllegalStateException("Stat ${this.name} name required but undefined")
}
}
@ -245,6 +251,14 @@ enum class Stat : RowRepresentable {
}
}
private val canBeUserSelected: Boolean
get() {
return when (this) {
WINNING_SESSION_COUNT, BB_SESSION_COUNT, RISK_OF_RUIN -> false
else -> true
}
}
override val viewType: Int = RowViewType.TITLE_VALUE.ordinal
}

@ -3,6 +3,7 @@ package net.pokeranalytics.android.model
import io.realm.Realm
import io.realm.Sort
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.Criteria.Bankrolls.comparison
import net.pokeranalytics.android.model.Criteria.Blinds.comparison
@ -54,6 +55,7 @@ fun getCombinations(queries: List<List<Query>>): List<Query> {
}
sealed class Criteria : RowRepresentable {
abstract class RealmCriteria : Criteria() {
inline fun <reified T : NameManageable> comparison(): List<Query> {
return compare<QueryCondition.QueryDataCondition<NameManageable>, T>()
@ -199,6 +201,30 @@ sealed class Criteria : RowRepresentable {
}
}
override val resId: Int?
get() {
return when (this) {
Bankrolls -> R.string.bankroll
Games -> R.string.game
TournamentNames -> R.string.tournament_name
Locations -> R.string.location
TournamentFeatures -> R.string.tournament_feature
Limits -> R.string.limit
TableSizes -> R.string.table_size
TournamentTypes -> R.string.tournament_type
MonthsOfYear -> R.string.month_of_the_year
DaysOfWeek -> R.string.day_of_the_week
SessionTypes -> R.string.cash_or_tournament
BankrollTypes -> R.string.live_or_online
DayPeriods -> R.string.weekdays_or_weekend
Years -> R.string.year
AllMonthsUpToNow -> R.string.month
Blinds -> R.string.blind
TournamentFees -> R.string.entry_fees
else -> null
}
}
companion object {
inline fun <reified S : QueryCondition.QueryDataCondition<NameManageable>, reified T : NameManageable> compare(): List<Query> {
val objects = mutableListOf<S>()

@ -152,7 +152,7 @@ enum class LiveData : Localizable {
}
/**
* Return the new entity title
* Return the new entity titleResId
*/
fun newEntityLocalizedTitle(context: Context): String {
return "${context.getString(R.string.new_str)} ${this.localizedTitle(context).toLowerCase()}"

@ -512,7 +512,7 @@ open class Session : RealmObject(), Savable, Editable, StaticRowRepresentableDat
}
/**
* Return the game title
* Return the game titleResId
* Example: NL Holdem
*/
fun getFormattedGame(): String {

@ -171,15 +171,15 @@ class HomeActivity : PokerAnalyticsActivity() {
//CLEAN
/*
0 -> {
toolbar.title = getString(R.string.feed)
toolbar.titleResId = getString(R.string.feed)
homeMenu?.findItem(R.id.queryWith)?.isVisible = false
}
1 -> {
toolbar.title = getString(R.string.stats)
toolbar.titleResId = getString(R.string.stats)
homeMenu?.findItem(R.id.queryWith)?.isVisible = false
}
2 -> {
toolbar.title = getString(R.string.services)
toolbar.titleResId = getString(R.string.services)
homeMenu?.findItem(R.id.queryWith)?.isVisible = false
}
*/

@ -50,7 +50,7 @@ class RowRepresentableAdapter(
if (row.viewType == RowViewType.TITLE_SWITCH.ordinal ||
row.viewType == RowViewType.LIST.ordinal) {
// Avoid to refresh the view because it will refresh itself
// Caution if we want to update the title for example
// Caution if we want to update the titleResId for example
return
}

@ -132,7 +132,7 @@ class BankrollDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)

@ -82,7 +82,7 @@ class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentable
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)

@ -115,7 +115,7 @@ class CurrenciesFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataS
val activity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = this.getString( R.string.currency)
activity.setSupportActionBar(toolbar)

@ -41,6 +41,17 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
private lateinit var dataListAdapter: RowRepresentableAdapter
private var lastItemClickedId: String = ""
/**
* Set fragment data
*/
fun setData(dataType: Int) {
this.dataType = LiveData.values()[dataType]
this.toolbar.title = this.dataType.localizedTitle(requireContext())
this.dataType?.let {
this.items = it.items(getRealm())
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_data_list, container, false)
@ -51,6 +62,49 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
initUI()
}
/**
* Init UI
*/
private fun initUI() {
val activity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the titleResId
toolbar.title = ""
activity.setSupportActionBar(toolbar)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext())
dataListAdapter = RowRepresentableAdapter(this, this)
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position ->
val itemId = (this.items[position] as Identifiable).id
deleteItem(dataListAdapter, items, itemId)
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
}
this.addButton.setOnClickListener {
this.dataType?.let {
EditableDataActivity.newInstance(
requireContext(),
dataType = it.ordinal,
primaryKey = null
)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_DETAILS && resultCode == Activity.RESULT_OK) {
@ -101,56 +155,4 @@ class DataListFragment : DeletableItemFragment(), LiveRowRepresentableDataSource
}
}
/**
* Init UI
*/
private fun initUI() {
val activity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
toolbar.title = ""
activity.setSupportActionBar(toolbar)
activity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
setHasOptionsMenu(true)
val viewManager = LinearLayoutManager(requireContext())
dataListAdapter = RowRepresentableAdapter(this, this)
val swipeToDelete = SwipeToDeleteCallback(dataListAdapter) { position ->
val itemId = (this.items[position] as Identifiable).id
deleteItem(dataListAdapter, items, itemId)
}
val itemTouchHelper = ItemTouchHelper(swipeToDelete)
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = dataListAdapter
itemTouchHelper.attachToRecyclerView(this)
}
this.addButton.setOnClickListener {
this.dataType?.let {
EditableDataActivity.newInstance(
requireContext(),
dataType = it.ordinal,
primaryKey = null
)
}
}
}
/**
* Set fragment data
*/
fun setData(dataType: Int) {
this.dataType = LiveData.values()[dataType]
this.toolbar.title = this.dataType.localizedTitle(requireContext())
this.dataType?.let {
this.items = it.items(getRealm())
}
}
}

@ -4,25 +4,152 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_report_creation.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.Criteria
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.ReportDisplay
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
class ReportCreationFragment : RealmFragment() {
class ReportCreationFragment : RealmFragment(), RowRepresentableDataSource, RowRepresentableDelegate {
class Process {
private lateinit var optionsAdapter: RowRepresentableAdapter
private var assistant = Assistant()
private var currentRows: List<RowRepresentable> = listOf()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_report_creation, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
this.optionsAdapter = RowRepresentableAdapter(this, this)
val viewManager = LinearLayoutManager(requireContext())
recyclerView.apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = optionsAdapter
}
this.updateUIWithCurrentStep()
this.next.setOnClickListener {
if (assistant.nextEnabled) {
this.assistant.nextStep()
if (this.assistant.step == Assistant.Step.FINALIZE) {
// launch report
val options = this.assistant.options
} else {
this.updateUIWithCurrentStep()
}
}
}
}
private fun updateUIWithCurrentStep() {
this.next.isVisible = this.assistant.nextButtonShouldAppear
this.next.text = requireContext().getString(this.assistant.nextButtonTitleResId)
this.next.isEnabled = this.assistant.nextEnabled
val rows = mutableListOf<RowRepresentable>()
this.assistant.titleResId?.let { titleResId ->
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = titleResId))
}
rows.addAll(this.assistant.dataSource)
this.currentRows = rows
this.optionsAdapter.notifyDataSetChanged()
}
// RowRepresentableDataSource
override fun adapterRows(): List<RowRepresentable>? {
return this.currentRows
}
override fun rowRepresentableForPosition(position: Int): RowRepresentable? {
return this.currentRows[position]
}
override fun numberOfRows(): Int {
return this.currentRows.size
}
override fun viewTypeForPosition(position: Int): Int {
return when (position) {
0 -> RowViewType.HEADER_TITLE.ordinal
else -> RowViewType.TITLE_CHECK.ordinal
}
}
override fun indexForRow(row: RowRepresentable): Int {
return this.currentRows.indexOf(row)
}
override fun isSelected(row: RowRepresentable): Boolean {
return this.assistant.isSelected(row)
}
// RowRepresentableDelegate
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
val newStep = this.assistant.onRowSelected(position - 1)
if (newStep) {
this.updateUIWithCurrentStep()
} else {
this.next.isEnabled = this.assistant.nextEnabled
this.optionsAdapter.refreshRow(row)
}
}
}
class Assistant {
var step: Step = Step.TYPE
var display: ReportDisplay? = null
var stats = listOf<Stat>()
var comparators = listOf<Criteria>()
var useFilter: Boolean? = null
var filter: Filter? = null
private var display: Calculator.Options.Display = Calculator.Options.Display.TABLE
private var stats = mutableListOf<Stat>()
private var comparators = mutableListOf<Criteria>()
private var useFilter: Boolean? = null
private var filter: Filter? = null
val options: Calculator.Options
get() {
return Calculator.Options(
this.display,
stats = this.stats,
criterias = this.comparators,
filter = this.filter,
userGenerated = true
)
}
enum class Step {
TYPE,
@ -32,25 +159,72 @@ class ReportCreationFragment : RealmFragment() {
FINALIZE
}
val nextStep: Step
get() {
return when (this.display) {
null -> Step.TYPE
/**
* Notifies the Assistant a row has been selected with a [position]
* Returns whether the step has changed
*/
fun onRowSelected(position: Int): Boolean {
val stepChanges = !this.nextButtonShouldAppear
when (this.step) {
Step.TYPE -> {
this.display = this.dataSource[position] as Calculator.Options.Display
this.nextStep()
}
Step.STAT -> {
val stat = this.dataSource[position] as Stat
if (this.stats.contains(stat)) {
this.stats.remove(stat)
} else {
this.stats.add(stat)
}
}
Step.COMPARATOR -> {
val comparator = this.dataSource[position] as Criteria
if (this.comparators.contains(comparator)) {
this.comparators.remove(comparator)
} else {
this.comparators.add(comparator)
}
}
Step.FILTER -> {
this.filter = this.dataSource[position] as Filter
}
else -> {
if (this.stats.isEmpty()) {
}
}
return stepChanges
}
fun isSelected(row: RowRepresentable): Boolean {
return when (this.step) {
Step.STAT -> this.stats.contains(row as Stat)
Step.COMPARATOR -> this.comparators.contains(row as Criteria)
else -> false
}
}
fun nextStep() {
this.step = this.nextStep
}
private val nextStep: Step
get() {
return if (this.stats.isEmpty()) {
Step.STAT
} else if (this.display!! == ReportDisplay.COMPARISON_GRAPH && this.comparators.isEmpty()) {
} else if (this.display == Calculator.Options.Display.COMPARISON && this.comparators.isEmpty()) {
Step.COMPARATOR
} else if (this.useFilter == null) {
Step.FILTER
} else {
Step.FINALIZE
}
}
}
}
fun titleForStep(step: Step) : Int? {
val titleResId: Int?
get() {
return when (step) {
Step.TYPE -> R.string.new_report_step_type
Step.STAT -> R.string.new_report_step_stat
@ -63,8 +237,12 @@ class ReportCreationFragment : RealmFragment() {
val dataSource: List<RowRepresentable>
get() {
return when (this.step) {
Step.TYPE -> return listOf(ReportDisplay.FIGURES, ReportDisplay.EVO_GRAPH, ReportDisplay.COMPARISON_GRAPH)
Step.STAT -> return Stat.values().toList()
Step.TYPE -> listOf(
Calculator.Options.Display.TABLE,
Calculator.Options.Display.EVOLUTION,
Calculator.Options.Display.COMPARISON
)
Step.STAT -> Stat.userSelectableList
Step.COMPARATOR -> Criteria.all
Step.FILTER -> {
val realm = Realm.getDefaultInstance()
@ -76,6 +254,16 @@ class ReportCreationFragment : RealmFragment() {
}
}
val nextEnabled: Boolean
get() {
return when (this.step) {
Step.STAT -> this.stats.isNotEmpty()
Step.COMPARATOR -> this.comparators.isNotEmpty()
Step.FILTER -> true
else -> false
}
}
val nextButtonShouldAppear: Boolean
get() {
return when (this.step) {
@ -84,7 +272,7 @@ class ReportCreationFragment : RealmFragment() {
}
}
val nextButtonTitle: Int
val nextButtonTitleResId: Int
get() {
return when (this.step) {
Step.FILTER -> R.string.launch_report
@ -93,10 +281,3 @@ class ReportCreationFragment : RealmFragment() {
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_report_creation, container, false)
}
}

@ -55,7 +55,7 @@ class ReportDetailsFragment : PokerAnalyticsFragment() {
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)

@ -152,7 +152,7 @@ class SessionFragment : RealmFragment(), RowRepresentableDelegate {
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)

@ -84,7 +84,7 @@ class StatisticDetailsFragment : PokerAnalyticsFragment() {
parentActivity = activity as PokerAnalyticsActivity
// Avoid a bug during setting the title
// Avoid a bug during setting the titleResId
toolbar.title = ""
parentActivity.setSupportActionBar(toolbar)

@ -26,7 +26,7 @@ data class DefaultLegendValues(
*/
open class LegendView : FrameLayout {
// open class Values(var title: String, var leftFormat: TextFormat, var rightFormat: TextFormat? = null)
// open class Values(var titleResId: String, var leftFormat: TextFormat, var rightFormat: TextFormat? = null)
// class MultiLineValues(
// var firstTitle: String,
// var secondTitle: String,

@ -80,7 +80,7 @@ interface Displayable : Localizable {
interface Localizable {
/**
* The resource identifier of the localized title
* The resource identifier of the localized titleResId
*/
val resId: Int?
get() {
@ -88,7 +88,7 @@ interface Localizable {
}
/**
* The localized title of the row
* The localized titleResId of the row
*/
fun localizedTitle(context: Context): String {
this.resId?.let {

@ -130,7 +130,7 @@ enum class RowViewType(private var layoutRes: Int) {
}
/**
* Display a generic row (title, value, container)
* Display a generic row (titleResId, value, container)
*/
@SuppressWarnings("ResourceType")
inner class RowViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {

@ -7,7 +7,7 @@ import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
/**
* A class to display a title (and a value) as a Row Representable object
* A class to display a titleResId (and a value) as a Row Representable object
*/
class CustomizableRowRepresentable(
var customViewType: RowViewType? = RowViewType.HEADER_TITLE,

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -10,11 +11,27 @@
app:title="@string/new_report"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintStart_toStartOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:layout_constraintBottom_toTopOf="@+id/next"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Next" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -5,17 +5,17 @@
<item
android:id="@+id/navigation_history"
android:icon="@drawable/ic_outline_history"
android:title="@string/feed" />
android:titleResId="@string/feed" />
<item
android:id="@+id/navigation_stats"
android:icon="@drawable/ic_outline_chart"
android:title="@string/stats" />
android:titleResId="@string/stats" />
<item
android:id="@+id/navigation_settings"
android:icon="@drawable/ic_outline_settings"
android:title="@string/services" />
android:titleResId="@string/services" />
-->

@ -27,7 +27,7 @@
<string name="new_report_step_type">Select your type of report</string>
<string name="new_report_step_stat">Select one or more statistics</string>
<string name="new_report_step_comparator">Select one or more comparison criteria</string>
<string name="new_report_step_filter">Select a filter if you want, 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="address">Address</string>

Loading…
Cancel
Save