Refactoring of the feed session adapter

csv
Laurent 6 years ago
parent 739ec41297
commit 54ff190b69
  1. 18
      app/src/main/java/net/pokeranalytics/android/model/realm/Filter.kt
  2. 120
      app/src/main/java/net/pokeranalytics/android/ui/adapter/FeedSessionRowRepresentableAdapter.kt
  3. 3
      app/src/main/java/net/pokeranalytics/android/ui/fragment/CalendarFragment.kt
  4. 61
      app/src/main/java/net/pokeranalytics/android/ui/fragment/FeedFragment.kt
  5. 3
      app/src/main/java/net/pokeranalytics/android/ui/fragment/StatisticsFragment.kt
  6. 7
      app/src/main/java/net/pokeranalytics/android/ui/fragment/components/RealmFragment.kt

@ -1,10 +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.*
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey import io.realm.annotations.PrimaryKey
import io.realm.kotlin.where import io.realm.kotlin.where
@ -153,19 +150,22 @@ open class Filter : RealmObject(), RowRepresentable, Editable, Deletable, Counta
} }
} }
inline fun <reified T : Filterable> results(firstField: String? = null, secondField: String? = null): RealmResults<T> { inline fun <reified T : Filterable> query(firstField: String? = null, secondField: String? = null): RealmQuery<T> {
val realmQuery = realm.where<T>() val realmQuery = realm.where<T>()
if (firstField != null && secondField != null) { if (firstField != null && secondField != null) {
return this.query.queryWith(realmQuery).distinct(firstField, secondField).findAll() return this.query.queryWith(realmQuery).distinct(firstField, secondField)
} }
if (firstField != null) { if (firstField != null) {
return this.query.queryWith(realmQuery).distinct(firstField).findAll() return this.query.queryWith(realmQuery).distinct(firstField)
} }
return this.query.queryWith(realmQuery).findAll() return this.query.queryWith(realmQuery)
}
inline fun <reified T : Filterable> results(firstField: String? = null, secondField: String? = null): RealmResults<T> {
return this.query<T>(firstField, secondField).findAll()
} }
val query: Query val query: Query

@ -6,12 +6,17 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.RealmResults import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.row_feed_session.view.* import kotlinx.android.synthetic.main.row_feed_session.view.*
import net.pokeranalytics.android.exceptions.PAIllegalStateException
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.BindableHolder import net.pokeranalytics.android.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowViewType import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.getMonthAndYear import net.pokeranalytics.android.util.extensions.getMonthAndYear
import timber.log.Timber import timber.log.Timber
import java.util.* import java.util.*
@ -20,24 +25,70 @@ import kotlin.collections.HashMap
/** /**
* An adapter capable of displaying a list of RowRepresentables * An adapter capable of displaying a list of RowRepresentables
* @param dataSource the datasource providing rows * The [delegate] is an object notified of UI actions
* @param delegate the delegate, notified of UI actions
*/ */
class FeedSessionRowRepresentableAdapter( class FeedSessionRowRepresentableAdapter(
var delegate: RowRepresentableDelegate? = null, private var realm: Realm,
var realmResults: RealmResults<Session>, var delegate: RowRepresentableDelegate? = null
var pendingRealmResults: RealmResults<Session>,
var distinctHeaders: RealmResults<Session>
) : ) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() { RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var headersPositions = HashMap<Int, Date?>() private lateinit var startedSessions: RealmResults<Session>
private lateinit var pendingSessions: RealmResults<Session>
private lateinit var sortedHeaders: SortedMap<Int, Date?> private lateinit var sortedHeaders: SortedMap<Int, Date?>
private var allSessions = mutableListOf<Session>()
var filter: Filter? = null
set(value) {
field = value
filterChanged()
refreshData()
}
init { init {
defineSessions() // all sessions
refreshData() refreshData()
} }
private fun defineSessions() {
this.startedSessions = requestNewQuery().isNotNull("startDate").findAll()
.sort("startDate", Sort.DESCENDING)
this.pendingSessions = requestNewQuery().isNull("startDate").findAll()
.sort("creationDate", Sort.DESCENDING)
// Timber.d(">>> startedSessions count = ${startedSessions.size}")
// Timber.d(">>> pendingSessions count = ${pendingSessions.size}")
// listeners
this.startedSessions.addChangeListener { _, _ ->
refreshData()
}
this.pendingSessions.addChangeListener { _, _ ->
refreshData()
}
}
private fun requestNewQuery() : RealmQuery<Session> {
this.filter?.let {
return it.query()
} ?: run {
return realm.where()
}
}
private fun filterChanged() {
this.startedSessions.removeAllChangeListeners()
this.pendingSessions.removeAllChangeListeners()
defineSessions()
}
/** /**
* Display a session view * Display a session view
*/ */
@ -88,7 +139,7 @@ class FeedSessionRowRepresentableAdapter(
} }
override fun getItemCount(): Int { override fun getItemCount(): Int {
return realmResults.size + pendingRealmResults.size + distinctHeaders.size return allSessions.size + sortedHeaders.size
} }
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
@ -110,27 +161,24 @@ class FeedSessionRowRepresentableAdapter(
context.getString(net.pokeranalytics.android.R.string.pending) context.getString(net.pokeranalytics.android.R.string.pending)
} else { } else {
// Else, return the formatted date // Else, return the formatted date
val realmHeaderPosition = if (pendingRealmResults.size > 0) sortedHeaders.keys.indexOf(position) - 1 else sortedHeaders.keys.indexOf(position) sortedHeaders[position]?.getMonthAndYear() ?: throw PAIllegalStateException("Null date should not happen there")
distinctHeaders[realmHeaderPosition]?.startDate?.getMonthAndYear() ?: ""
// val realmHeaderPosition = sortedHeaders.keys.indexOf(position)
// distinctHeaders[realmHeaderPosition]?.startDate?.getMonthAndYear() ?: throw PAIllegalStateException("Null date should not happen there")
} }
} }
return NULL_TEXT throw PAIllegalStateException("Any position should always have a header, position = $position")
// return NULL_TEXT
} }
fun sessionIdForPosition(position: Int): String? { fun sessionIdForPosition(position: Int): String? {
val session = this.getSessionForPosition(position) return this.getSessionForPosition(position)?.id
return session?.id
} }
/** /**
* Get real index * Get real index
*/ */
private fun getSessionForPosition(position: Int): Session? { private fun getSessionForPosition(position: Int): Session? {
return if (pendingRealmResults.size > 0 && position < pendingRealmResults.size + 1) {
// If we have pending session & the position is between these sessions
pendingRealmResults[position - 1]
} else {
// Else, return the correct session
// Row position // Row position
var headersBefore = 0 var headersBefore = 0
@ -141,9 +189,8 @@ class FeedSessionRowRepresentableAdapter(
break break
} }
} }
// Timber.d("getSessionForPosition = ${position}, headersBefore = $headersBefore")
realmResults[position - headersBefore - pendingRealmResults.size] return allSessions[position - headersBefore]
}
} }
/** /**
@ -151,12 +198,15 @@ class FeedSessionRowRepresentableAdapter(
*/ */
fun refreshData() { fun refreshData() {
headersPositions.clear() allSessions.clear()
allSessions.addAll(this.pendingSessions)
allSessions.addAll(this.startedSessions)
// If we have pending sessions, set the first header to null // allSessions.forEach {
if (pendingRealmResults.size > 0) { // Timber.d(">>> startdate = ${it.startDate}, creationDate = ${it.creationDate}")
headersPositions[0] = null // }
}
val headersPositions = HashMap<Int, Date?>()
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
@ -166,14 +216,22 @@ class FeedSessionRowRepresentableAdapter(
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
// Add headers if the date doesn't exist yet // Add headers if the date doesn't exist yet
for ((index, session) in realmResults.withIndex()) { for ((index, session) in allSessions.withIndex()) {
calendar.time = session.startDate ?: session.creationDate // Timber.d("/// $index > date = ${session.startDate}")
val startDate = session.startDate
if (startDate == null) {
headersPositions[0] = null
} else {
calendar.time = startDate
if (checkHeaderCondition(calendar, previousYear, previousMonth)) { if (checkHeaderCondition(calendar, previousYear, previousMonth)) {
headersPositions[index + headersPositions.size + pendingRealmResults.size] = session.startDate ?: session.creationDate // Timber.d("ADDS HEADER for position= ${index + headersPositions.size}, date = ${session.startDate}")
headersPositions[index + headersPositions.size] = startDate
previousYear = calendar.get(Calendar.YEAR) previousYear = calendar.get(Calendar.YEAR)
previousMonth = calendar.get(Calendar.MONTH) previousMonth = calendar.get(Calendar.MONTH)
} }
} }
}
sortedHeaders = headersPositions.toSortedMap() sortedHeaders = headersPositions.toSortedMap()
@ -183,7 +241,7 @@ class FeedSessionRowRepresentableAdapter(
/** /**
* Check if we need to add a header * Check if we need to add a header
* Can be change to manage different condition * Can be changed to manage different condition
*/ */
private fun checkHeaderCondition(currentCalendar: Calendar, previousYear: Int, previousMonth: Int) : Boolean { private fun checkHeaderCondition(currentCalendar: Calendar, previousYear: Int, previousMonth: Int) : Boolean {
return currentCalendar.get(Calendar.YEAR) == previousYear && currentCalendar.get(Calendar.MONTH) < previousMonth || (currentCalendar.get(Calendar.YEAR) < previousYear) return currentCalendar.get(Calendar.YEAR) == previousYear && currentCalendar.get(Calendar.MONTH) < previousMonth || (currentCalendar.get(Calendar.YEAR) < previousYear)

@ -8,6 +8,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_calendar.* import kotlinx.android.synthetic.main.fragment_calendar.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -117,7 +118,7 @@ class CalendarFragment : RealmFragment(), CoroutineScope, StaticRowRepresentable
override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java) override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java)
override fun entitiesChanged(clazz: Class<out RealmModel>) { override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
launchStatComputation() launchStatComputation()
} }

@ -59,7 +59,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
private lateinit var feedSessionAdapter: FeedSessionRowRepresentableAdapter private lateinit var feedSessionAdapter: FeedSessionRowRepresentableAdapter
private lateinit var feedTransactionAdapter: FeedTransactionRowRepresentableAdapter private lateinit var feedTransactionAdapter: FeedTransactionRowRepresentableAdapter
private lateinit var realmSessions: RealmResults<Session>
// private lateinit var realmSessions: RealmResults<Session>
private lateinit var realmTransactions: RealmResults<Transaction> private lateinit var realmTransactions: RealmResults<Transaction>
private lateinit var betaLimitDate: Date private lateinit var betaLimitDate: Date
@ -68,14 +69,23 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
private var selectedTransaction: Transaction? = null private var selectedTransaction: Transaction? = null
private var selectedTransactionPosition: Int = -1 private var selectedTransactionPosition: Int = -1
override val observedEntities: List<Class<out RealmModel>> = listOf(Session::class.java, Transaction::class.java) override val observedEntities: List<Class<out RealmModel>> = listOf(Transaction::class.java)
override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
super.entitiesChanged(clazz, results)
Timber.d("=== results count = ${results.size}")
override fun entitiesChanged(clazz: Class<out RealmModel>) { results.forEach { model ->
super.entitiesChanged(clazz) if (model is Session) {
Timber.d("++++ sd = ${model.startDate}, year = ${model.year}, month=${model.month}")
} else {
Timber.d(model.toString())
}
}
when (clazz.kotlin) { when (clazz.kotlin) {
Session::class -> { Session::class -> {
this.feedSessionAdapter.refreshData() // this.feedSessionAdapter.refreshData()
} }
Transaction::class -> { Transaction::class -> {
this.feedTransactionAdapter.refreshData() this.feedTransactionAdapter.refreshData()
@ -112,7 +122,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
throw PAIllegalStateException("Session not found for duplicate at position: ${info.position}") throw PAIllegalStateException("Session not found for duplicate at position: ${info.position}")
} }
} }
else -> { } else -> {
}
} }
return true return true
@ -150,7 +161,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
realmSessions.removeAllChangeListeners()
realmTransactions.removeAllChangeListeners() realmTransactions.removeAllChangeListeners()
} }
@ -187,6 +197,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/ */
private fun initUI() { private fun initUI() {
this.feedSessionAdapter = FeedSessionRowRepresentableAdapter(getRealm(), this)
registerForContextMenu(this.recyclerView) registerForContextMenu(this.recyclerView)
val messageToShow: Preferences.FeedMessage? = Preferences.feedMessageToShow(requireContext()) val messageToShow: Preferences.FeedMessage? = Preferences.feedMessageToShow(requireContext())
@ -257,30 +269,15 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
} }
private fun loadSessions(filter: Filter? = null) { private fun loadSessions(filter: Filter? = null) {
val sessionFilter: Filter? = filter?.let {
if (it.filterableType == FilterableType.SESSION) {
it
} else {
null
}
}
// Sessions when (filter?.filterableType) {
this.realmSessions = FilterableType.SESSION -> {
sessionFilter?.results() ?: run { getRealm().where<Session>().isNotNull("startDate").findAll() } this.feedSessionAdapter.filter = filter
this.realmSessions = this.realmSessions.sort("startDate", Sort.DESCENDING) }
else -> {
val pendingSessions = sessionFilter?.let { this.feedSessionAdapter.filter = null
getRealm().where<Session>().alwaysFalse().findAll()
} ?: run {
getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING)
} }
var distinctDateSessions = sessionFilter?.results("year", "month") ?: run {
getRealm().where<Session>().distinct("year", "month").findAll()
} }
distinctDateSessions = distinctDateSessions.sort("startDate", Sort.DESCENDING)
this.feedSessionAdapter =
FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions)
} }
private fun loadTransactions(filter: Filter? = null) { private fun loadTransactions(filter: Filter? = null) {
@ -323,7 +320,13 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
return return
} }
SessionActivity.newInstanceforResult(this, isTournament, sessionId = sessionId, duplicate = duplicate, requestCode = RequestCode.NEW_SESSION.value) SessionActivity.newInstanceforResult(
this,
isTournament,
sessionId = sessionId,
duplicate = duplicate,
requestCode = RequestCode.NEW_SESSION.value
)
newSessionCreated = true newSessionCreated = true
} }

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async import kotlinx.coroutines.async
@ -74,7 +75,7 @@ class StatisticsFragment : FilterableFragment() {
override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java) override val observedEntities: List<Class<out RealmModel>> = listOf(ComputableResult::class.java)
override fun entitiesChanged(clazz: Class<out RealmModel>) { override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
this.launchStatComputation() this.launchStatComputation()
} }

@ -7,6 +7,7 @@ import android.view.ViewGroup
import io.realm.Realm import io.realm.Realm
import io.realm.RealmModel import io.realm.RealmModel
import io.realm.RealmResults import io.realm.RealmResults
import timber.log.Timber
open class RealmFragment : PokerAnalyticsFragment() { open class RealmFragment : PokerAnalyticsFragment() {
@ -26,8 +27,8 @@ open class RealmFragment : PokerAnalyticsFragment() {
this.observedEntities.forEach { this.observedEntities.forEach {
val realmResults = realm.where(it).findAll() val realmResults = realm.where(it).findAll()
realmResults.addChangeListener { _,_ -> realmResults.addChangeListener { t, _ ->
this.entitiesChanged(it) this.entitiesChanged(it, t)
} }
this.observedRealmResults.add(realmResults) this.observedRealmResults.add(realmResults)
@ -61,6 +62,6 @@ open class RealmFragment : PokerAnalyticsFragment() {
/** /**
* The method called when a change happened in any RealmResults * The method called when a change happened in any RealmResults
*/ */
open fun entitiesChanged(clazz: Class<out RealmModel>) {} open fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {}
} }
Loading…
Cancel
Save