Merge pull request #1449 from Andries-Smit/feat/relative-date

Feat relative date
This commit is contained in:
Milos Kozak 2022-03-16 13:52:41 +01:00 committed by GitHub
commit 873ef227db
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 100 additions and 40 deletions

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.activities.fragments
import android.annotation.SuppressLint
import android.graphics.Paint
import android.os.Bundle
import android.util.Log
import android.util.SparseArray
import android.view.*
import android.widget.CompoundButton
@ -190,7 +189,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
removeActionMode?.let { it.finish() }
removeActionMode?.finish()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@ -206,9 +205,9 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
val profile = profileFunction.getProfile() ?: return
val ml = mealLinks[position]
val sameDayPrevious = position > 0 && dateUtil.isSameDay(timestamp(ml), timestamp(mealLinks[position - 1]))
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(timestamp(ml))
val newDay = position == 0 || !dateUtil.isSameDayGroup(timestamp(ml), timestamp(mealLinks[position - 1]))
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(timestamp(ml), rh) else ""
// Metadata
holder.binding.metadataLayout.visibility = (ml.bolusCalculatorResult != null && (ml.bolusCalculatorResult.isValid || showInvalidated)).toVisibility()
@ -272,7 +271,7 @@ class TreatmentsBolusCarbsFragment : DaggerFragment() {
}
holder.binding.calculation.tag = ml
val nextTimestamp = if (mealLinks.size != position + 1) timestamp(mealLinks[position + 1]) else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(timestamp(ml), nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(timestamp(ml), nextTimestamp).toVisibility()
}
override fun getItemCount() = mealLinks.size

View file

@ -149,7 +149,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
removeActionMode?.let { it.finish() }
removeActionMode?.finish()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@ -165,9 +165,9 @@ class TreatmentsCareportalFragment : DaggerFragment() {
val therapyEvent = therapyList[position]
holder.binding.ns.visibility = (therapyEvent.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.invalid.visibility = therapyEvent.isValid.not().toVisibility()
val sameDayPrevious = position > 0 && dateUtil.isSameDay(therapyEvent.timestamp, therapyList[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(therapyEvent.timestamp)
val newDay = position == 0 || !dateUtil.isSameDayGroup(therapyEvent.timestamp, therapyList[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(therapyEvent.timestamp, rh) else ""
holder.binding.time.text = dateUtil.timeString(therapyEvent.timestamp)
holder.binding.duration.text = if (therapyEvent.duration == 0L) "" else dateUtil.niceTimeScalar(therapyEvent.duration, rh)
holder.binding.note.text = therapyEvent.note
@ -185,7 +185,7 @@ class TreatmentsCareportalFragment : DaggerFragment() {
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
}
val nextTimestamp = if (therapyList.size != position + 1) therapyList[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(therapyEvent.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(therapyEvent.timestamp, nextTimestamp).toVisibility()
}
override fun getItemCount() = therapyList.size

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.activities.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.util.SparseArray
import android.view.*
@ -114,7 +113,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
removeActionMode?.let { it.finish() }
removeActionMode?.finish()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@ -131,10 +130,9 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
holder.binding.ns.visibility = (extendedBolus.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.ph.visibility = (extendedBolus.interfaceIDs.pumpId != null).toVisibility()
holder.binding.invalid.visibility = extendedBolus.isValid.not().toVisibility()
val sameDayPrevious = position > 0 && dateUtil.isSameDay(extendedBolus.timestamp, extendedBolusList[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(extendedBolus.timestamp)
@SuppressLint("SetTextI18n")
val newDay = position == 0 || !dateUtil.isSameDayGroup(extendedBolus.timestamp, extendedBolusList[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(extendedBolus.timestamp, rh) else ""
if (extendedBolus.isInProgress(dateUtil)) {
holder.binding.time.text = dateUtil.timeString(extendedBolus.timestamp)
holder.binding.time.setTextColor(rh.gc(R.color.colorActive))
@ -162,7 +160,7 @@ class TreatmentsExtendedBolusesFragment : DaggerFragment() {
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
}
val nextTimestamp = if (extendedBolusList.size != position + 1) extendedBolusList[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(extendedBolus.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(extendedBolus.timestamp, nextTimestamp).toVisibility()
}
override fun getItemCount() = extendedBolusList.size

View file

@ -184,9 +184,9 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
val profileSwitch = profileSwitchList[position]
holder.binding.ph.visibility = (profileSwitch is ProfileSealed.EPS).toVisibility()
holder.binding.ns.visibility = (profileSwitch.interfaceIDs_backing?.nightscoutId != null).toVisibility()
val sameDayPrevious = position > 0 && dateUtil.isSameDay(profileSwitch.timestamp, profileSwitchList[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(profileSwitch.timestamp)
val newDay = position == 0 || !dateUtil.isSameDayGroup(profileSwitch.timestamp, profileSwitchList[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(profileSwitch.timestamp, rh) else ""
holder.binding.time.text = dateUtil.timeString(profileSwitch.timestamp)
holder.binding.duration.text = rh.gs(R.string.format_mins, T.msecs(profileSwitch.duration ?: 0L).mins())
holder.binding.name.text =
@ -213,7 +213,7 @@ class TreatmentsProfileSwitchFragment : DaggerFragment() {
holder.binding.clone.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
holder.binding.spacer.visibility = (profileSwitch is ProfileSealed.PS).toVisibility()
val nextTimestamp = if (profileSwitchList.size != position + 1) profileSwitchList[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(profileSwitch.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(profileSwitch.timestamp, nextTimestamp).toVisibility()
}
override fun getItemCount() = profileSwitchList.size

View file

@ -154,7 +154,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
removeActionMode?.let { it.finish() }
removeActionMode?.finish()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@ -185,9 +185,9 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
}
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
}
val sameDayPrevious = position > 0 && dateUtil.isSameDay(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(tempTarget.timestamp)
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempTarget.timestamp, tempTargetList[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(tempTarget.timestamp, rh) else ""
holder.binding.time.text = dateUtil.timeRangeString(tempTarget.timestamp, tempTarget.end)
holder.binding.duration.text = rh.gs(R.string.format_mins, T.msecs(tempTarget.duration).mins())
holder.binding.low.text = tempTarget.lowValueToUnitsToString(units)
@ -201,7 +201,7 @@ class TreatmentsTempTargetFragment : DaggerFragment() {
}
)
val nextTimestamp = if (tempTargetList.size != position + 1) tempTargetList[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(tempTarget.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempTarget.timestamp, nextTimestamp).toVisibility()
}
override fun getItemCount() = tempTargetList.size

View file

@ -1,7 +1,6 @@
package info.nightscout.androidaps.activities.fragments
import android.os.Bundle
import android.util.Log
import android.util.SparseArray
import android.view.*
import androidx.appcompat.widget.Toolbar
@ -155,7 +154,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
@Synchronized
override fun onDestroyView() {
super.onDestroyView()
removeActionMode?.let { it.finish() }
removeActionMode?.finish()
binding.recyclerview.adapter = null // avoid leaks
_binding = null
}
@ -172,7 +171,9 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
holder.binding.ph.visibility = (tempBasal.interfaceIDs.pumpId != null).toVisibility()
val sameDayPrevious = position > 0 && dateUtil.isSameDay(tempBasal.timestamp, tempBasalList[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(tempBasal.timestamp)
val newDay = position == 0 || !dateUtil.isSameDayGroup(tempBasal.timestamp, tempBasalList[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(tempBasal.timestamp, rh) else ""
if (tempBasal.isInProgress) {
holder.binding.time.text = dateUtil.timeString(tempBasal.timestamp)
holder.binding.time.setTextColor(rh.gc(R.color.colorActive))
@ -206,7 +207,7 @@ class TreatmentsTemporaryBasalsFragment : DaggerFragment() {
holder.binding.cbRemove.isChecked = selectedItems.get(position) != null
}
val nextTimestamp = if (tempBasalList.size != position + 1) tempBasalList[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(tempBasal.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(tempBasal.timestamp, nextTimestamp).toVisibility()
}
override fun getItemCount() = tempBasalList.size

View file

@ -128,9 +128,9 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
override fun onBindViewHolder(holder: UserEntryViewHolder, position: Int) {
val current = entries[position]
val sameDayPrevious = position > 0 && dateUtil.isSameDay(current.timestamp, entries[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(current.timestamp)
val newDay = position == 0 || !dateUtil.isSameDayGroup(current.timestamp, entries[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(current.timestamp, rh) else ""
holder.binding.time.text = dateUtil.timeStringWithSeconds(current.timestamp)
holder.binding.action.text = userEntryPresentationHelper.actionToColoredString(current.action)
holder.binding.notes.text = current.note
@ -140,7 +140,7 @@ class TreatmentsUserEntryFragment : DaggerFragment() {
holder.binding.values.text = userEntryPresentationHelper.listToPresentationString(current.values)
holder.binding.values.visibility = if (holder.binding.values.text != "") View.VISIBLE else View.GONE
val nextTimestamp = if (entries.size != position + 1) entries[position + 1].timestamp else 0L
holder.binding.delimiter.visibility = dateUtil.isSameDay(current.timestamp, nextTimestamp).toVisibility()
holder.binding.delimiter.visibility = dateUtil.isSameDayGroup(current.timestamp, nextTimestamp).toVisibility()
}
inner class UserEntryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

View file

@ -147,9 +147,9 @@ class BGSourceFragment : DaggerFragment() {
val glucoseValue = glucoseValues[position]
holder.binding.ns.visibility = (glucoseValue.interfaceIDs.nightscoutId != null).toVisibility()
holder.binding.invalid.visibility = (!glucoseValue.isValid).toVisibility()
val sameDayPrevious = position > 0 && dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp)
holder.binding.date.visibility = sameDayPrevious.not().toVisibility()
holder.binding.date.text = dateUtil.dateString(glucoseValue.timestamp)
val newDay = position == 0 || !dateUtil.isSameDay(glucoseValue.timestamp, glucoseValues[position - 1].timestamp)
holder.binding.date.visibility = newDay.toVisibility()
holder.binding.date.text = if (newDay) dateUtil.dateStringRelative(glucoseValue.timestamp, rh) else ""
holder.binding.time.text = dateUtil.timeString(glucoseValue.timestamp)
holder.binding.value.text = glucoseValue.valueToUnitsString(profileFunction.getUnits())
holder.binding.direction.setImageResource(glucoseValue.trendArrow.directionToIcon())

View file

@ -24,6 +24,8 @@ import java.util.stream.Collectors
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.abs
import kotlin.math.ceil
import kotlin.math.floor
/**
* The Class DateUtil. A simple wrapper around SimpleDateFormat to ease the handling of iso date string <-> date obj
@ -56,8 +58,6 @@ class DateUtil @Inject constructor(private val context: Context) {
* Render date
*
* @param date the date obj
* @param format - if not specified, will use FORMAT_DATE_ISO
* @param tz - tz to set to, if not specified uses local timezone
* @return the iso-formatted date string
*/
fun toISOString(date: Long): String {
@ -104,6 +104,26 @@ class DateUtil @Inject constructor(private val context: Context) {
return df.format(mills)
}
fun dateStringRelative(mills: Long, rh: ResourceHelper): String {
val df = DateFormat.getDateInstance(DateFormat.SHORT)
val day = df.format(mills)
val beginOfToday = beginOfDay(now())
return if (mills < now()) // Past
when {
mills > beginOfToday -> rh.gs(R.string.today)
mills > beginOfToday - T.days(1).msecs() -> rh.gs(R.string.yesterday)
mills > beginOfToday - T.days(7).msecs() -> dayAgo(mills, rh, true)
else -> day
}
else // Future
when {
mills < beginOfToday + T.days(1).msecs() -> rh.gs(R.string.later_today)
mills < beginOfToday + T.days(2).msecs() -> rh.gs(R.string.tomorrow)
mills < beginOfToday + T.days(7).msecs() -> dayAgo(mills, rh, true)
else -> day
}
}
fun dateStringShort(mills: Long): String {
var format = "MM/dd"
if (android.text.format.DateFormat.is24HourFormat(context)) {
@ -167,6 +187,33 @@ class DateUtil @Inject constructor(private val context: Context) {
return rh.gs(R.string.hoursago, hours)
}
fun dayAgo(time: Long, rh: ResourceHelper, round: Boolean = false): String {
var days = (now() - time) / 1000.0 / 60 / 60 / 24
if (round) {
if (now() > time) {
days = ceil(days)
return rh.gs(R.string.days_ago_round, days)
} else {
days = floor(days)
return rh.gs(R.string.in_days_round, days)
}
}
return if (now() > time)
rh.gs(R.string.days_ago, days)
else
rh.gs(R.string.in_days, days)
}
fun beginOfDay(mills: Long): Long {
val givenDate = Calendar.getInstance()
givenDate.timeInMillis = mills
givenDate[Calendar.HOUR_OF_DAY] = 0
givenDate[Calendar.MINUTE] = 0
givenDate[Calendar.SECOND] = 0
givenDate[Calendar.MILLISECOND] = 0
return givenDate.timeInMillis
}
fun timeStringFromSeconds(seconds: Int): String {
val cached = timeStrings[seconds.toLong()]
if (cached != null) return cached
@ -220,6 +267,13 @@ class DateUtil @Inject constructor(private val context: Context) {
fun isSameDay(timestamp1: Long, timestamp2: Long) = isSameDay(Date(timestamp1), Date(timestamp2))
fun isSameDayGroup(timestamp1: Long, timestamp2: Long): Boolean {
val now = now()
if (timestamp1 < now && timestamp2 > now || timestamp1 > now && timestamp2 < now)
return false
return isSameDay(Date(timestamp1), Date(timestamp2))
}
//Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
fun computeDiff(date1: Long, date2: Long): Map<TimeUnit, Long> {
val units: MutableList<TimeUnit> = ArrayList(EnumSet.allOf(TimeUnit::class.java))

View file

@ -204,6 +204,10 @@
<string name="minago">%1$d m ago</string>
<string name="minago_long">%1$d minutes ago</string>
<string name="hoursago">%1$.1f h ago</string>
<string name="days_ago">%1$.1f days ago</string>
<string name="days_ago_round">%1$.0f days ago</string>
<string name="in_days">in %1$.0f days</string>
<string name="in_days_round">in %1$.0f days</string>
<string name="shorthour">h</string>
<string name="days">days</string>
<string name="hours">hours</string>
@ -219,6 +223,10 @@
<string name="unit_weeks">weeks</string>
<string name="shortminute">m</string>
<string name="shortday">d</string>
<string name="later_today">Later today</string>
<string name="tomorrow">Tomorrow</string>
<string name="today">Today</string>
<string name="yesterday">Yesterday</string>
<!-- Protection-->
<string name="wrongpassword">Wrong password</string>