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. 142
      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. 95
      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
import android.content.Context
import io.realm.Realm
import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.*
import io.realm.annotations.Ignore
import io.realm.annotations.PrimaryKey
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>()
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) {
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

@ -6,12 +6,17 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.realm.Realm
import io.realm.RealmQuery
import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
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.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.getMonthAndYear
import timber.log.Timber
import java.util.*
@ -20,24 +25,70 @@ import kotlin.collections.HashMap
/**
* An adapter capable of displaying a list of RowRepresentables
* @param dataSource the datasource providing rows
* @param delegate the delegate, notified of UI actions
* The [delegate] is an object notified of UI actions
*/
class FeedSessionRowRepresentableAdapter(
var delegate: RowRepresentableDelegate? = null,
var realmResults: RealmResults<Session>,
var pendingRealmResults: RealmResults<Session>,
var distinctHeaders: RealmResults<Session>
private var realm: Realm,
var delegate: RowRepresentableDelegate? = null
) :
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 var allSessions = mutableListOf<Session>()
var filter: Filter? = null
set(value) {
field = value
filterChanged()
refreshData()
}
init {
defineSessions() // all sessions
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
*/
@ -88,7 +139,7 @@ class FeedSessionRowRepresentableAdapter(
}
override fun getItemCount(): Int {
return realmResults.size + pendingRealmResults.size + distinctHeaders.size
return allSessions.size + sortedHeaders.size
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
@ -110,40 +161,36 @@ class FeedSessionRowRepresentableAdapter(
context.getString(net.pokeranalytics.android.R.string.pending)
} else {
// Else, return the formatted date
val realmHeaderPosition = if (pendingRealmResults.size > 0) sortedHeaders.keys.indexOf(position) - 1 else sortedHeaders.keys.indexOf(position)
distinctHeaders[realmHeaderPosition]?.startDate?.getMonthAndYear() ?: ""
sortedHeaders[position]?.getMonthAndYear() ?: throw PAIllegalStateException("Null date should not happen there")
// 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? {
val session = this.getSessionForPosition(position)
return session?.id
return this.getSessionForPosition(position)?.id
}
/**
* Get real index
*/
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
var headersBefore = 0
for (key in sortedHeaders.keys) {
if (position > key) {
headersBefore++
} else {
break
}
}
realmResults[position - headersBefore - pendingRealmResults.size]
// Row position
var headersBefore = 0
for (key in sortedHeaders.keys) {
if (position > key) {
headersBefore++
} else {
break
}
}
// Timber.d("getSessionForPosition = ${position}, headersBefore = $headersBefore")
return allSessions[position - headersBefore]
}
/**
@ -151,12 +198,15 @@ class FeedSessionRowRepresentableAdapter(
*/
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
if (pendingRealmResults.size > 0) {
headersPositions[0] = null
}
// allSessions.forEach {
// Timber.d(">>> startdate = ${it.startDate}, creationDate = ${it.creationDate}")
// }
val headersPositions = HashMap<Int, Date?>()
val start = System.currentTimeMillis()
@ -166,12 +216,20 @@ class FeedSessionRowRepresentableAdapter(
val calendar = Calendar.getInstance()
// Add headers if the date doesn't exist yet
for ((index, session) in realmResults.withIndex()) {
calendar.time = session.startDate ?: session.creationDate
if (checkHeaderCondition(calendar, previousYear, previousMonth)) {
headersPositions[index + headersPositions.size + pendingRealmResults.size] = session.startDate ?: session.creationDate
previousYear = calendar.get(Calendar.YEAR)
previousMonth = calendar.get(Calendar.MONTH)
for ((index, session) in allSessions.withIndex()) {
// 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)) {
// Timber.d("ADDS HEADER for position= ${index + headersPositions.size}, date = ${session.startDate}")
headersPositions[index + headersPositions.size] = startDate
previousYear = calendar.get(Calendar.YEAR)
previousMonth = calendar.get(Calendar.MONTH)
}
}
}
@ -183,7 +241,7 @@ class FeedSessionRowRepresentableAdapter(
/**
* 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 {
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 io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.android.synthetic.main.fragment_calendar.*
import kotlinx.coroutines.CoroutineScope
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 fun entitiesChanged(clazz: Class<out RealmModel>) {
override fun entitiesChanged(clazz: Class<out RealmModel>, results: RealmResults<out RealmModel>) {
launchStatComputation()
}

@ -59,7 +59,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
private lateinit var feedSessionAdapter: FeedSessionRowRepresentableAdapter
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 betaLimitDate: Date
@ -68,14 +69,23 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
private var selectedTransaction: Transaction? = null
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>) {
super.entitiesChanged(clazz)
results.forEach { model ->
if (model is Session) {
Timber.d("++++ sd = ${model.startDate}, year = ${model.year}, month=${model.month}")
} else {
Timber.d(model.toString())
}
}
when (clazz.kotlin) {
Session::class -> {
this.feedSessionAdapter.refreshData()
// this.feedSessionAdapter.refreshData()
}
Transaction::class -> {
this.feedTransactionAdapter.refreshData()
@ -112,7 +122,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
throw PAIllegalStateException("Session not found for duplicate at position: ${info.position}")
}
}
else -> { }
else -> {
}
}
return true
@ -150,7 +161,6 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
override fun onDestroyView() {
super.onDestroyView()
realmSessions.removeAllChangeListeners()
realmTransactions.removeAllChangeListeners()
}
@ -187,6 +197,8 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
*/
private fun initUI() {
this.feedSessionAdapter = FeedSessionRowRepresentableAdapter(getRealm(), this)
registerForContextMenu(this.recyclerView)
val messageToShow: Preferences.FeedMessage? = Preferences.feedMessageToShow(requireContext())
@ -245,7 +257,7 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
val sdf = SimpleDateFormat("dd/M/yyyy hh:mm", Locale.getDefault())
betaLimitDate = sdf.parse("17/7/2019 10:00")
this.currentFilterable = FilterableType.SESSION
this.currentFilterable = FilterableType.SESSION
val viewManager = SmoothScrollLinearLayoutManager(requireContext())
recyclerView.apply {
@ -257,30 +269,15 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
}
private fun loadSessions(filter: Filter? = null) {
val sessionFilter: Filter? = filter?.let {
if (it.filterableType == FilterableType.SESSION) {
it
} else {
null
}
}
// Sessions
this.realmSessions =
sessionFilter?.results() ?: run { getRealm().where<Session>().isNotNull("startDate").findAll() }
this.realmSessions = this.realmSessions.sort("startDate", Sort.DESCENDING)
val pendingSessions = sessionFilter?.let {
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()
when (filter?.filterableType) {
FilterableType.SESSION -> {
this.feedSessionAdapter.filter = filter
}
else -> {
this.feedSessionAdapter.filter = null
}
}
distinctDateSessions = distinctDateSessions.sort("startDate", Sort.DESCENDING)
this.feedSessionAdapter =
FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions)
}
private fun loadTransactions(filter: Filter? = null) {
@ -323,7 +320,13 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
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
}
@ -344,9 +347,9 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
* Delete selected transaction
*/
private fun deleteSelectedTransaction() {
getRealm().executeTransaction {
selectedTransaction?.deleteFromRealm()
}
getRealm().executeTransaction {
selectedTransaction?.deleteFromRealm()
}
selectedTransactionPosition = -1
}
@ -372,18 +375,18 @@ class FeedFragment : FilterableFragment(), RowRepresentableDelegate {
this.loadTransactions(filter)
filter?.let {
when (it.filterableType) {
FilterableType.SESSION -> {
recyclerView.adapter = feedSessionAdapter
this.selectTab(Tab.SESSIONS)
}
FilterableType.TRANSACTION -> {
recyclerView.adapter = feedTransactionAdapter
this.selectTab(Tab.TRANSACTIONS)
}
else -> {
}
}
when (it.filterableType) {
FilterableType.SESSION -> {
recyclerView.adapter = feedSessionAdapter
this.selectTab(Tab.SESSIONS)
}
FilterableType.TRANSACTION -> {
recyclerView.adapter = feedTransactionAdapter
this.selectTab(Tab.TRANSACTIONS)
}
else -> {
}
}
adapterHasBeenSet = true
}

@ -8,6 +8,7 @@ import android.view.View
import android.view.ViewGroup
import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
@ -74,7 +75,7 @@ class StatisticsFragment : FilterableFragment() {
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()
}

@ -7,6 +7,7 @@ import android.view.ViewGroup
import io.realm.Realm
import io.realm.RealmModel
import io.realm.RealmResults
import timber.log.Timber
open class RealmFragment : PokerAnalyticsFragment() {
@ -26,8 +27,8 @@ open class RealmFragment : PokerAnalyticsFragment() {
this.observedEntities.forEach {
val realmResults = realm.where(it).findAll()
realmResults.addChangeListener { _,_ ->
this.entitiesChanged(it)
realmResults.addChangeListener { t, _ ->
this.entitiesChanged(it, t)
}
this.observedRealmResults.add(realmResults)
@ -61,6 +62,6 @@ open class RealmFragment : PokerAnalyticsFragment() {
/**
* 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