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

dev
Laurent 7 years ago
commit f3f6deb070
  1. 2
      app/src/main/java/net/pokeranalytics/android/PokerAnalyticsApplication.kt
  2. 15
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  3. 73
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomField.kt
  4. 45
      app/src/main/java/net/pokeranalytics/android/model/realm/CustomFieldEntry.kt
  5. 158
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/CustomFieldDataFragment.kt
  6. 1
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/EditableDataFragment.kt
  7. 4
      app/src/main/java/net/pokeranalytics/android/ui/view/RowViewType.kt
  8. 9
      app/src/main/res/drawable/ic_reorder.xml
  9. 87
      app/src/main/res/layout/fragment_custom_view.xml

@ -34,7 +34,7 @@ class PokerAnalyticsApplication : Application() {
Realm.init(this)
val realmConfiguration = RealmConfiguration.Builder()
.name(Realm.DEFAULT_REALM_NAME)
.schemaVersion(7)
.schemaVersion(6)
.migration(PokerAnalyticsMigration())
.initialData(Seed(this))
.build()

@ -2,11 +2,10 @@ package net.pokeranalytics.android.model.migrations
import io.realm.DynamicRealm
import io.realm.RealmMigration
import net.pokeranalytics.android.model.realm.CustomFieldEntry
import timber.log.Timber
class PokerAnalyticsMigration : RealmMigration {
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
@ -103,20 +102,18 @@ class PokerAnalyticsMigration : RealmMigration {
it.addField("year", Integer::class.java)
it.addField("dayOfMonth", Integer::class.java)
}
currentVersion++
schema.create("CustomFieldEntry")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addField("value", String::class.java).setNullable("type", false)
it.addField("order", Integer::class.java).setNullable("type", false)
}
// Migrate to version 7
if (currentVersion == 6) {
Timber.d("*** Running migration ${currentVersion + 1}")
schema.get("CustomField")?.let {
it.addField("type", Integer::class.java).setNullable("type", false)
it.addField("duplicateValue", Boolean::class.java)
it.addRealmListField("entries", String::class.java)
it.addRealmListField("entries", CustomFieldEntry::class.java)
}
currentVersion++
}
}
override fun equals(other: Any?): Boolean {

@ -11,10 +11,14 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList
open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDataSource, RowRepresentable {
@ -25,16 +29,6 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
AMOUNT(R.string.amount)
}
companion object {
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.addAll(CustomFieldRow.values())
rows
}
}
@PrimaryKey
override var id = UUID.randomUUID().toString()
@ -43,8 +37,13 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
// Migration
var type: Int = Type.LIST.ordinal
set(value) {
field = value
this.updateRowRepresentation()
}
var duplicateValue: Boolean = false
var entries: RealmList<String> = RealmList()
var entries: RealmList<CustomFieldEntry> = RealmList()
// @todo
@ -56,6 +55,8 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
@Ignore
override val viewType: Int = RowViewType.TITLE_VALUE_ARROW.ordinal
@Ignore
private var rowRepresentation: List<RowRepresentable> = mutableListOf()
override fun adapterRows(): List<RowRepresentable>? {
return rowRepresentation
@ -93,4 +94,54 @@ open class CustomField : RealmObject(), NameManageable, StaticRowRepresentableDa
return R.string.relationship_error
}
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
is CustomFieldEntry -> row.editingDescriptors(
mapOf(
"defaultValue" to row.value
)
)
else -> null
}
}
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
rows.add(SimpleRow.NAME)
rows.add(CustomFieldRow.TYPE)
if (type == Type.LIST.ordinal && entries.size >= 0) {
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, R.string.items_list))
if (entries.isNotEmpty()) {
Timber.d("entries: ${entries.size}")
entries.sortBy { it.order }
rows.addAll(entries)
}
}
Timber.d("rows: ${rows.size}")
return rows
}
fun updateRowRepresentation() {
this.rowRepresentation = this.updatedRowRepresentationForCurrentState()
}
/**
* Add entry
*/
fun addEntry() {
val entry = CustomFieldEntry()
entry.order = (entries.lastOrNull()?.order ?: 0) + 1
entries.add(entry)
updateRowRepresentation()
}
/**
*
*/
fun deleteEntry() {
}
}

@ -0,0 +1,45 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import android.text.InputType
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
open class CustomFieldEntry : RealmObject(), RowRepresentable {
@PrimaryKey
var id = UUID.randomUUID().toString()
var value: String = ""
var order: Int = 0
@Ignore
override val viewType: Int = RowViewType.TITLE.ordinal
@Ignore
override val bottomSheetType: BottomSheetType = BottomSheetType.EDIT_TEXT
override fun localizedTitle(context: Context): String {
return context.getString(R.string.value)
}
override fun getDisplayName(): String {
return if (value.isNotEmpty()) value else NULL_TEXT
}
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowRepresentableEditDescriptor>? {
val defaultValue: Any? by map
return arrayListOf(
RowRepresentableEditDescriptor(defaultValue, R.string.value, InputType.TYPE_CLASS_TEXT)
)
}
}

@ -1,10 +1,20 @@
package net.pokeranalytics.android.ui.fragment.data
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.fragment_custom_view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.CustomFieldEntry
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
@ -24,9 +34,75 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
return this.item as CustomField
}
private val oldRows: ArrayList<RowRepresentable> = ArrayList()
private val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {
var dragFrom = -1
var dragTo = -1
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
return if (viewHolder.adapterPosition <= 2) {
return 0
} else {
makeFlag(
ItemTouchHelper.ACTION_STATE_DRAG, ItemTouchHelper.DOWN
or ItemTouchHelper.UP or ItemTouchHelper.START or ItemTouchHelper.END
)
}
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
if (target.adapterPosition <= 2) {
return false
}
val fromPosition = viewHolder.adapterPosition
val toPosition = target.adapterPosition
if (dragFrom == -1) {
dragFrom = viewHolder.adapterPosition - 1
}
dragTo = target.adapterPosition - 1
rowRepresentableAdapter.notifyItemMoved(fromPosition, toPosition)
return true
}
override fun onMoved(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, fromPos: Int, target: RecyclerView.ViewHolder, toPos: Int, x: Int, y: Int) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
Collections.swap(customField.entries, fromPos - (CustomFieldRow.values().size + 1), toPos - (CustomFieldRow.values().size + 1))
customField.entries.forEachIndexed { index, rowRepresentable ->
val entry = rowRepresentable as CustomFieldEntry
entry.order = index
}
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
super.clearView(recyclerView, viewHolder)
dragFrom = -1
dragTo = -1
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
})
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
return inflater.inflate(R.layout.fragment_custom_view, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
shouldOpenKeyboard = false
//shouldOpenKeyboard = false
initUI()
}
override fun getDataSource(): RowRepresentableDataSource {
@ -61,31 +137,91 @@ class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDa
override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
return when (row) {
SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.customField.name))
is CustomFieldEntry -> row.editingDescriptors(mapOf("defaultValue" to row.value))
else -> null
}
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
when (row) {
is CustomFieldEntry -> {
val data = customField.editDescriptors(row)
Timber.d("data: $data")
BottomSheetFragment.create(fragmentManager, row, this, data, false)
}
else -> super.onRowSelected(position, row, fromAction)
}
}
override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
super.onRowValueChanged(value, row)
Timber.d("onRowValueChanged: $row => $value")
when (row) {
is CustomFieldEntry -> {
row.value = value as String? ?: ""
rowRepresentableAdapter.refreshRow(row)
}
CustomFieldRow.TYPE -> {
customField.updateValue(value, row)
updateUI()
updateAdapterUI()
}
}
}
//rowRepresentableAdapter.refreshRow(row)
/**
* Init UI
*/
private fun initUI() {
customField.updateRowRepresentation()
bottomBar.translationY = 72f.px
bottomBar.visibility = View.VISIBLE
/*
GlobalScope.launch(Dispatchers.Main) {
delay(200)
when(row) {
TransactionRow.BANKROLL -> onRowSelected(0, TransactionRow.TYPE)
TransactionRow.TYPE -> onRowSelected(0, TransactionRow.AMOUNT)
TransactionRow.AMOUNT -> onRowSelected(0, TransactionRow.DATE)
TransactionRow.DATE -> onRowSelected(0, TransactionRow.COMMENT)
itemTouchHelper.attachToRecyclerView(recyclerView)
addItem.setOnClickListener {
customField.addEntry()
updateAdapterUI()
}
updateUI()
updateAdapterUI()
}
/**
* Update UI
*/
private fun updateUI() {
if (customField.type == CustomField.Type.LIST.ordinal) {
bottomBar.animate().translationY(0f.px)
.setInterpolator(FastOutSlowInInterpolator())
.start()
} else {
bottomBar.animate().translationY(72f.px)
.setInterpolator(FastOutSlowInInterpolator())
.start()
}
}
/**
* Update adapter UI
*/
private fun updateAdapterUI() {
rowRepresentableAdapter.notifyDataSetChanged()
/*
//TODO: Code to animate changes
// Test:
// not really, i agree with your part about performance but notifyDataSetChanged() does not kill animations,
// to animate using notifyDataSetChanged(), a) call setHasStableIds(true) on your RecyclerView.Adapter object and b)
// override getItemId inside your Adapter to return a unique long value for each row and check it out, the animations do work
customField.adapterRows()?.let {
val diffResult = DiffUtil.calculateDiff(RowRepresentableDiffCallback(it, oldRows))
rowRepresentableAdapter.updateRows(diffResult)
oldRows.clear()
oldRows.addAll(it)
}
*/
}

@ -70,6 +70,7 @@ open class EditableDataFragment : RealmFragment(), RowRepresentableDelegate {
}
override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
BottomSheetFragment.create(fragmentManager, row, this, getDataSource().editDescriptors(row))
}

@ -410,6 +410,9 @@ enum class RowViewType(private var layoutRes: Int) {
itemView.findViewById<ChipGroup>(R.id.chipGroup)?.let { chipGroup ->
chipGroup.removeAllViews()
chipGroup.setOnCheckedChangeListener(null)
CustomField.Type.values().forEach { type ->
val chip = Chip(itemView.context)
chip.id = type.ordinal
@ -432,7 +435,6 @@ enum class RowViewType(private var layoutRes: Int) {
adapter.delegate?.onRowValueChanged(CustomField.Type.values()[checkedId], row)
}
})
}
}
}

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M3,15h18v-2L3,13v2zM3,19h18v-2L3,17v2zM3,11h18L21,9L3,9v2zM3,5v2h18L21,5L3,5z"/>
</vector>

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="128dp"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:collapsedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.CollapsedTitleAppearance"
app:contentScrim="?attr/colorPrimary"
app:expandedTitleGravity="bottom"
app:expandedTitleMarginStart="72dp"
app:expandedTitleTextAppearance="@style/PokerAnalyticsTheme.Toolbar.ExpandedTitleAppearance"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:title="Poker Analytics"
app:titleTextColor="@color/white" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:visibility="gone"
app:contentInsetStart="8dp"
tools:visibility="visible">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/addItem"
android:layout_width="32dp"
android:layout_height="32dp"
android:padding="4dp"
android:background="?selectableItemBackgroundBorderless"
android:src="@drawable/ic_add"
android:tint="@color/green" />
</FrameLayout>
</com.google.android.material.bottomappbar.BottomAppBar>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Loading…
Cancel
Save