Working on player comments

feature/players
Aurelien Hubert 6 years ago
parent 48868992a4
commit 54b6457fc9
  1. 9
      app/src/main/java/net/pokeranalytics/android/model/migrations/PokerAnalyticsMigration.kt
  2. 79
      app/src/main/java/net/pokeranalytics/android/model/realm/Comment.kt
  3. 96
      app/src/main/java/net/pokeranalytics/android/model/realm/Player.kt
  4. 50
      app/src/main/java/net/pokeranalytics/android/ui/fragment/data/PlayerDataFragment.kt
  5. 26
      app/src/main/java/net/pokeranalytics/android/ui/view/rowrepresentable/CustomFieldRow.kt
  6. 2
      app/src/main/res/layout/fragment_custom_view.xml
  7. 52
      app/src/main/res/layout/fragment_player.xml

@ -2,7 +2,9 @@ package net.pokeranalytics.android.model.migrations
import io.realm.DynamicRealm import io.realm.DynamicRealm
import io.realm.RealmMigration import io.realm.RealmMigration
import net.pokeranalytics.android.model.realm.Comment
import timber.log.Timber import timber.log.Timber
import java.util.*
class PokerAnalyticsMigration : RealmMigration { class PokerAnalyticsMigration : RealmMigration {
@ -155,10 +157,17 @@ class PokerAnalyticsMigration : RealmMigration {
// Migrate to version 8 // Migrate to version 8
if (currentVersion == 7) { if (currentVersion == 7) {
schema.create("Comment")?.let {
it.addField("id", String::class.java).setRequired("id", true)
it.addField("content", String::class.java)
it.addField("date", Date::class.java)
}
schema.get("Player")?.let { schema.get("Player")?.let {
it.addField("summary", String::class.java).setRequired("summary", true) it.addField("summary", String::class.java).setRequired("summary", true)
it.addField("color", Int::class.java).setNullable("color", true) it.addField("color", Int::class.java).setNullable("color", true)
it.addField("picture", String::class.java) it.addField("picture", String::class.java)
it.addRealmListField("comments", Comment::class.java)
} }
currentVersion++ currentVersion++
} }

@ -0,0 +1,79 @@
package net.pokeranalytics.android.model.realm
import android.content.Context
import androidx.fragment.app.Fragment
import io.realm.Realm
import io.realm.RealmObject
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ModelException
import net.pokeranalytics.android.model.interfaces.DeleteValidityStatus
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*
open class Comment : RealmObject(), Manageable, RowRepresentable {
@PrimaryKey
override var id = UUID.randomUUID().toString()
var content: String = ""
var date: Date = Date()
@Ignore
override val realmObjectClass: Class<out Identifiable> = Comment::class.java
@Ignore
override val viewType: Int = RowViewType.TITLE.ordinal
@Ignore
override val inputFragmentType: InputFragmentType = InputFragmentType.EDIT_TEXT_MULTI_LINES
override fun localizedTitle(context: Context): String {
return context.getString(R.string.comment)
}
override fun getDisplayName(context: Context): String {
return if (content.isNotEmpty()) content else NULL_TEXT
}
override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (parent == null) return
if (parent !is RowRepresentableDelegate) return
val data = RowEditableDataSource()
data.append(this.content, R.string.value)
InputFragment.buildAndShow(this, parent, data, isDeletable = true)
}
override fun updateValue(value: Any?, row: RowRepresentable) {
this.content = value as String? ?: ""
}
override fun isValidForSave(): Boolean {
return true
}
override fun alreadyExists(realm: Realm): Boolean {
return realm.where(this::class.java).notEqualTo("id", this.id).findAll().isNotEmpty()
}
override fun getFailedSaveMessage(status: SaveValidityStatus): Int {
throw ModelException("${this::class.java} getFailedSaveMessage for $status not handled")
}
override fun isValidForDelete(realm: Realm): Boolean {
return true
}
override fun getFailedDeleteMessage(status: DeleteValidityStatus): Int {
return R.string.cf_entry_delete_popup_message
}
}

@ -2,6 +2,7 @@ package net.pokeranalytics.android.model.realm
import android.content.Context import android.content.Context
import io.realm.Realm import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmObject import io.realm.RealmObject
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
@ -13,38 +14,38 @@ import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
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.PlayerRow import net.pokeranalytics.android.ui.view.rowrepresentable.PlayerRow
import net.pokeranalytics.android.util.NULL_TEXT import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.isSameDay
import net.pokeranalytics.android.util.extensions.mediumDate
import java.util.* import java.util.*
open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresentableDataSource, RowRepresentable { open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresentableDataSource, RowRepresentable {
companion object {
val rowRepresentation: List<RowRepresentable> by lazy {
val rows = ArrayList<RowRepresentable>()
rows.add(PlayerRow.IMAGE)
rows.add(PlayerRow.NAME)
rows.add(PlayerRow.SUMMARY)
rows
}
}
@Ignore
override val realmObjectClass: Class<out Identifiable> = Player::class.java
@PrimaryKey @PrimaryKey
override var id = UUID.randomUUID().toString() override var id = UUID.randomUUID().toString()
// The name of the player // The name of the player
override var name: String = "" override var name: String = ""
@Ignore
override val viewType: Int = RowViewType.ROW_PLAYER.ordinal
// New fields // New fields
var summary: String = "" var summary: String = ""
var color: Int? = null var color: Int? = null
var picture: String? = null var picture: String? = null
var comments: RealmList<Comment> = RealmList()
@Ignore
override val realmObjectClass: Class<out Identifiable> = Player::class.java
@Ignore
override val viewType: Int = RowViewType.ROW_PLAYER.ordinal
@Ignore
private var rowRepresentation: List<RowRepresentable> = mutableListOf()
@Ignore
private var commentsToDelete: ArrayList<Comment> = ArrayList()
override fun isValidForDelete(realm: Realm): Boolean { override fun isValidForDelete(realm: Realm): Boolean {
@ -80,6 +81,42 @@ open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresent
} }
} }
/**
* Update the row representation
*/
private fun updatedRowRepresentationForCurrentState(): List<RowRepresentable> {
val rows = ArrayList<RowRepresentable>()
rows.add(PlayerRow.IMAGE)
rows.add(PlayerRow.NAME)
rows.add(PlayerRow.SUMMARY)
if (comments.size > 0) {
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, R.string.comments))
val currentCommentCalendar = Calendar.getInstance()
val currentDateCalendar = Calendar.getInstance()
val commentsToDisplay = ArrayList<Comment>()
commentsToDisplay.addAll(comments)
commentsToDisplay.sortByDescending { it.date }
commentsToDisplay.forEachIndexed { index, comment ->
currentCommentCalendar.time = comment.date
if (!currentCommentCalendar.isSameDay(currentDateCalendar) || index == 0) {
currentDateCalendar.time = currentCommentCalendar.time
rows.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, title = currentDateCalendar.time.mediumDate()))
}
rows.add(comment)
}
}
return rows
}
/** /**
* Return if the player has a picture * Return if the player has a picture
*/ */
@ -87,4 +124,31 @@ open class Player : RealmObject(), NameManageable, Deletable, StaticRowRepresent
return picture != null && picture?.isNotEmpty() == true return picture != null && picture?.isNotEmpty() == true
} }
/**
* Update row representation
*/
fun updateRowRepresentation() {
this.rowRepresentation = this.updatedRowRepresentationForCurrentState()
}
/**
* Add an entry
*/
fun addComent(): Comment {
val entry = Comment()
this.comments.add(entry)
updateRowRepresentation()
return entry
}
/**
* Delete an entry
*/
fun deleteComment(comment: Comment) {
commentsToDelete.add(comment)
this.comments.remove(comment)
updateRowRepresentation()
}
} }

@ -8,7 +8,9 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_player.*
import net.pokeranalytics.android.R import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Comment
import net.pokeranalytics.android.model.realm.Player import net.pokeranalytics.android.model.realm.Player
import net.pokeranalytics.android.ui.activity.ColorPickerActivity import net.pokeranalytics.android.ui.activity.ColorPickerActivity
import net.pokeranalytics.android.ui.activity.components.MediaActivity import net.pokeranalytics.android.ui.activity.components.MediaActivity
@ -105,9 +107,47 @@ class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSou
} }
override fun onRowValueChanged(value: Any?, row: RowRepresentable) { override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
when (row) {
is Comment -> {
row.updateValue(value, row)
player.updateRowRepresentation()
rowRepresentableAdapter.notifyDataSetChanged()
}
else -> {
super.onRowValueChanged(value, row) super.onRowValueChanged(value, row)
if (row == PlayerRow.NAME) {
rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE)
}
}
}
}
override fun onRowDeleted(row: RowRepresentable) {
super.onRowDeleted(row)
when (row) { when (row) {
PlayerRow.NAME -> rowRepresentableAdapter.refreshRow(PlayerRow.IMAGE) is Comment -> {
if (!row.isValidForDelete(getRealm())) {
} else {
player.deleteComment(row)
rowRepresentableAdapter.notifyDataSetChanged()
}
/*
if (!row.isValidForDelete(getRealm())) {
val status = row.getDeleteStatus(requireContext(), getRealm())
val message = row.getFailedDeleteMessage(status)
showAlertDialog(requireContext(), R.string.cf_entry_delete_popup_title, message, showCancelButton = true, positiveAction = {
customField.deleteEntry(row)
rowRepresentableAdapter.notifyDataSetChanged()
})
} else {
customField.deleteEntry(row)
rowRepresentableAdapter.notifyDataSetChanged()
}
*/
}
} }
} }
@ -117,9 +157,17 @@ class PlayerDataFragment : EditableDataFragment(), StaticRowRepresentableDataSou
private fun initUI() { private fun initUI() {
mediaActivity = parentActivity as MediaActivity? mediaActivity = parentActivity as MediaActivity?
player.updateRowRepresentation()
if (!deleteButtonShouldAppear) { if (!deleteButtonShouldAppear) {
onRowSelected(0, SimpleRow.NAME) onRowSelected(0, SimpleRow.NAME)
} }
addComment.setOnClickListener {
val comment = player.addComent()
rowRepresentableAdapter.notifyDataSetChanged()
onRowSelected(-1, comment)
}
} }
/** /**

@ -7,8 +7,8 @@ import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.input.InputFragment import net.pokeranalytics.android.ui.fragment.components.input.InputFragment
import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType import net.pokeranalytics.android.ui.fragment.components.input.InputFragmentType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowEditableDataSource import net.pokeranalytics.android.ui.view.RowEditableDataSource
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
enum class CustomFieldRow : RowRepresentable { enum class CustomFieldRow : RowRepresentable {
@ -64,30 +64,6 @@ enum class CustomFieldRow : RowRepresentable {
return list return list
} }
/*
override fun editingDescriptors(map: Map<String, Any?>): ArrayList<RowEditableDescriptor>? {
return when (type) {
Type.LIST.uniqueIdentifier -> {
val defaultValue: Any? by map
val data: RealmList<CustomFieldEntry>? by map
arrayListOf(
RowEditableDescriptor(defaultValue, staticData = data)
)
}
else -> {
val defaultValue: Double? by map
arrayListOf(
RowEditableDescriptor(
defaultValue, inputType = InputType.TYPE_CLASS_NUMBER
or InputType.TYPE_NUMBER_FLAG_DECIMAL
or InputType.TYPE_NUMBER_FLAG_SIGNED
)
)
}
}
}
*/
override fun startEditing(dataSource: Any?, parent: Fragment?) { override fun startEditing(dataSource: Any?, parent: Fragment?) {
if (dataSource == null) return if (dataSource == null) return
if (dataSource !is CustomField) return if (dataSource !is CustomField) return

@ -9,6 +9,8 @@
android:id="@+id/nestedScrollView" android:id="@+id/nestedScrollView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingBottom="56dp"
android:clipToPadding="false"
android:fillViewport="true" android:fillViewport="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior">

@ -1,13 +1,14 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:animateLayoutChanges="true"> android:animateLayoutChanges="true">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar" android:id="@+id/appBar"
android:layout_width="0dp" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:theme="@style/PokerAnalyticsTheme.Toolbar.Session" android:theme="@style/PokerAnalyticsTheme.Toolbar.Session"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
@ -21,10 +22,22 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:title="@string/stats" /> app:title="@string/player" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:paddingBottom="56dp"
android:clipToPadding="false"
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 <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView" android:id="@+id/recyclerView"
@ -33,6 +46,37 @@
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appBar" /> app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.bottomappbar.BottomAppBar
android:id="@+id/bottomBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
app:contentInsetEnd="8dp"
app:contentInsetStart="8dp"
app:layout_constraintBottom_toBottomOf="@+id/recyclerView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/addComment"
style="@style/PokerAnalyticsTheme.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="@string/add_comment" />
</FrameLayout>
</com.google.android.material.bottomappbar.BottomAppBar>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Loading…
Cancel
Save