BGSourceFragment UI tweaks and recognize history change
This commit is contained in:
parent
7bc7388f06
commit
fe53b733d0
3 changed files with 128 additions and 11 deletions
|
@ -417,6 +417,8 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
|
||||||
try {
|
try {
|
||||||
getDaoBgReadings().update(bgReading);
|
getDaoBgReadings().update(bgReading);
|
||||||
openHumansUploader.enqueueBGReading(bgReading);
|
openHumansUploader.enqueueBGReading(bgReading);
|
||||||
|
aapsLogger.debug(LTag.DATABASE, "BG: Updating record from: "+ bgReading.toString());
|
||||||
|
scheduleBgHistoryChange(bgReading.date); // trigger cache invalidation
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
aapsLogger.error("Unhandled exception", e);
|
aapsLogger.error("Unhandled exception", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,22 +7,27 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import dagger.android.support.DaggerFragment
|
import dagger.android.support.DaggerFragment
|
||||||
import info.nightscout.androidaps.MainApp
|
import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.db.BgReading
|
import info.nightscout.androidaps.db.BgReading
|
||||||
|
import info.nightscout.androidaps.events.EventNewBG
|
||||||
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
import info.nightscout.androidaps.interfaces.DatabaseHelperInterface
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHistoryBgData
|
||||||
import info.nightscout.androidaps.plugins.source.BGSourceFragment.RecyclerViewAdapter.BgReadingsViewHolder
|
import info.nightscout.androidaps.plugins.source.BGSourceFragment.RecyclerViewAdapter.BgReadingsViewHolder
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.ListDiffCallback
|
||||||
|
import info.nightscout.androidaps.utils.ListUpdateCallbackHelper
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.extensions.toVisibility
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
@ -30,6 +35,7 @@ import kotlinx.android.synthetic.main.bgsource_fragment.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class BGSourceFragment : DaggerFragment() {
|
class BGSourceFragment : DaggerFragment() {
|
||||||
|
|
||||||
@Inject lateinit var rxBus: RxBusWrapper
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@ -51,14 +57,24 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
bgsource_recyclerview.setHasFixedSize(true)
|
bgsource_recyclerview.setHasFixedSize(true)
|
||||||
bgsource_recyclerview.layoutManager = LinearLayoutManager(view.context)
|
bgsource_recyclerview.layoutManager = LinearLayoutManager(view.context)
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
bgsource_recyclerview.adapter = RecyclerViewAdapter(MainApp.getDbHelper().getAllBgreadingsDataFromTime(now - MILLS_TO_THE_PAST, false))
|
bgsource_recyclerview.adapter = RecyclerViewAdapter(getBgData(now))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
bgsource_recyclerview?.adapter = null // avoid leaks
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
.toObservable(EventNewBG::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ updateGUI() }) { fabricPrivacy.logException(it) }
|
||||||
|
)
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventNewHistoryBgData::class.java)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe({ updateGUI() }) { fabricPrivacy.logException(it) }
|
.subscribe({ updateGUI() }) { fabricPrivacy.logException(it) }
|
||||||
)
|
)
|
||||||
|
@ -73,30 +89,62 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
|
|
||||||
private fun updateGUI() {
|
private fun updateGUI() {
|
||||||
val now = System.currentTimeMillis()
|
val now = System.currentTimeMillis()
|
||||||
bgsource_recyclerview?.swapAdapter(RecyclerViewAdapter(MainApp.getDbHelper().getAllBgreadingsDataFromTime(now - MILLS_TO_THE_PAST, false)), true)
|
(bgsource_recyclerview?.adapter as? RecyclerViewAdapter)?.setData(getBgData(now))
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class RecyclerViewAdapter internal constructor(private var bgReadings: List<BgReading>) : RecyclerView.Adapter<BgReadingsViewHolder>() {
|
private fun getBgData(now: Long) = MainApp.getDbHelper()
|
||||||
|
.getAllBgreadingsDataFromTime(now - MILLS_TO_THE_PAST, false)
|
||||||
|
|
||||||
|
inner class RecyclerViewAdapter internal constructor(bgReadings: List<BgReading>) : RecyclerView.Adapter<BgReadingsViewHolder>() {
|
||||||
|
|
||||||
|
private var callbackHelper = ListUpdateCallbackHelper(this) { bgsource_recyclerview?.smoothScrollToPosition(0) }
|
||||||
|
|
||||||
|
private val currentData: MutableList<BgReading> = mutableListOf<BgReading>().also { it.addAll(bgReadings) }
|
||||||
|
|
||||||
|
fun setData(newList: List<BgReading>) {
|
||||||
|
val diffResult = DiffUtil.calculateDiff(getListDiffCallback(ArrayList(newList), ArrayList(currentData)))
|
||||||
|
currentData.clear()
|
||||||
|
currentData.addAll(newList)
|
||||||
|
diffResult.dispatchUpdatesTo(callbackHelper)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getListDiffCallback(newItems: List<BgReading>, oldItems: List<BgReading>): ListDiffCallback<BgReading> =
|
||||||
|
object : ListDiffCallback<BgReading>(newItems, oldItems) {
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
|
val new = newItems[newItemPosition]
|
||||||
|
val old = oldItems[oldItemPosition]
|
||||||
|
return new.hasValidNS == old.hasValidNS &&
|
||||||
|
new.isValid == old.isValid &&
|
||||||
|
new.date == old.date &&
|
||||||
|
new.value == old.value
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
newItems[newItemPosition].date == oldItems[oldItemPosition].date
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): BgReadingsViewHolder {
|
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): BgReadingsViewHolder {
|
||||||
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.bgsource_item, viewGroup, false)
|
val v = LayoutInflater.from(viewGroup.context).inflate(R.layout.bgsource_item, viewGroup, false)
|
||||||
return BgReadingsViewHolder(v)
|
return BgReadingsViewHolder(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: BgReadingsViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: BgReadingsViewHolder, position: Int) {
|
||||||
val bgReading = bgReadings[position]
|
val bgReading = currentData[position]
|
||||||
holder.ns.visibility = if (NSUpload.isIdValid(bgReading._id)) View.VISIBLE else View.GONE
|
holder.ns.visibility = (NSUpload.isIdValid(bgReading._id)).toVisibility()
|
||||||
holder.invalid.visibility = if (!bgReading.isValid) View.VISIBLE else View.GONE
|
holder.invalid.visibility = bgReading.isValid.not().toVisibility()
|
||||||
holder.date.text = dateUtil.dateAndTimeString(bgReading.date)
|
holder.date.text = dateUtil.dateAndTimeString(bgReading.date)
|
||||||
holder.value.text = bgReading.valueToUnitsToString(profileFunction.getUnits())
|
holder.value.text = bgReading.valueToUnitsToString(profileFunction.getUnits())
|
||||||
holder.direction.setImageResource(bgReading.directionToIcon(databaseHelper))
|
holder.direction.setImageResource(bgReading.directionToIcon(databaseHelper))
|
||||||
holder.remove.tag = bgReading
|
holder.remove.tag = bgReading
|
||||||
|
holder.remove.visibility = bgReading.isValid.toVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return bgReadings.size
|
return currentData.size
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class BgReadingsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
inner class BgReadingsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
var date: TextView = itemView.findViewById(R.id.bgsource_date)
|
var date: TextView = itemView.findViewById(R.id.bgsource_date)
|
||||||
var value: TextView = itemView.findViewById(R.id.bgsource_value)
|
var value: TextView = itemView.findViewById(R.id.bgsource_value)
|
||||||
var direction: ImageView = itemView.findViewById(R.id.bgsource_direction)
|
var direction: ImageView = itemView.findViewById(R.id.bgsource_direction)
|
||||||
|
@ -112,7 +160,6 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
|
OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.removerecord), text, Runnable {
|
||||||
bgReading.isValid = false
|
bgReading.isValid = false
|
||||||
MainApp.getDbHelper().update(bgReading)
|
MainApp.getDbHelper().update(bgReading)
|
||||||
updateGUI()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,4 +167,7 @@ class BGSourceFragment : DaggerFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val BgReading.hasValidNS
|
||||||
|
get() = NSUpload.isIdValid(this._id)
|
|
@ -0,0 +1,65 @@
|
||||||
|
package info.nightscout.androidaps.utils
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListUpdateCallback
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
|
||||||
|
open class ListDiffCallback<T>(private val newItems: List<T>, private val oldItems: List<T>) : DiffUtil.Callback() {
|
||||||
|
|
||||||
|
override fun getOldListSize(): Int = oldItems.size
|
||||||
|
|
||||||
|
override fun getNewListSize(): Int = newItems.size
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the DiffUtil to decide whether two object represent the same Item.
|
||||||
|
* <p>
|
||||||
|
* For example, if your items have unique ids, this method should check their id equality.
|
||||||
|
*
|
||||||
|
* @param oldItemPosition The position of the item in the old list
|
||||||
|
* @param newItemPosition The position of the item in the new list
|
||||||
|
* @return True if the two items represent the same object or false if they are different.
|
||||||
|
*/
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
newItems[newItemPosition] == oldItems[oldItemPosition]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the DiffUtil when it wants to check whether two items have the same data.
|
||||||
|
* DiffUtil uses this information to detect if the contents of an item has changed.
|
||||||
|
* <p>
|
||||||
|
* DiffUtil uses this method to check equality instead of {@link Object#equals(Object)}
|
||||||
|
* so that you can change its behavior depending on your UI.
|
||||||
|
* For example, if you are using DiffUtil with a
|
||||||
|
* {@link RecyclerView.Adapter RecyclerView.Adapter}, you should
|
||||||
|
* return whether the items' visual representations are the same.
|
||||||
|
* <p>
|
||||||
|
* This method is called only if {@link #areItemsTheSame(int, int)} returns
|
||||||
|
* {@code true} for these items.
|
||||||
|
*
|
||||||
|
* @param oldItemPosition The position of the item in the old list
|
||||||
|
* @param newItemPosition The position of the item in the new list which replaces the
|
||||||
|
* oldItem
|
||||||
|
* @return True if the contents of the items are the same or false if they are different.
|
||||||
|
*/
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
newItems[newItemPosition] == oldItems[oldItemPosition]
|
||||||
|
}
|
||||||
|
|
||||||
|
class ListUpdateCallbackHelper(val adapter: RecyclerView.Adapter<*>, val insertCallback: (Int) -> Unit) : ListUpdateCallback {
|
||||||
|
|
||||||
|
override fun onChanged(position: Int, count: Int, payload: Any?) {
|
||||||
|
adapter.notifyItemRangeChanged(position, count, payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInserted(position: Int, count: Int) {
|
||||||
|
adapter.notifyItemRangeInserted(position, count)
|
||||||
|
insertCallback(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMoved(fromPosition: Int, toPosition: Int) {
|
||||||
|
adapter.notifyItemMoved(fromPosition, toPosition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRemoved(position: Int, count: Int) {
|
||||||
|
adapter.notifyItemRangeRemoved(position, count)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue