simplify :app-wear-shared:shared
This commit is contained in:
parent
b7bc33c1d8
commit
81eb4f3a1c
|
@ -4,10 +4,18 @@ import android.content.Context
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.interfaces.L
|
import info.nightscout.rx.interfaces.L
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.impl.logging.AAPSLoggerProduction
|
||||||
import info.nightscout.shared.impl.logging.LImpl
|
import info.nightscout.shared.impl.logging.LImpl
|
||||||
|
import info.nightscout.shared.impl.rx.AapsSchedulersImpl
|
||||||
|
import info.nightscout.shared.impl.rx.bus.RxBusImpl
|
||||||
import info.nightscout.shared.impl.sharedPreferences.SPImplementation
|
import info.nightscout.shared.impl.sharedPreferences.SPImplementation
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
import info.nightscout.shared.utils.DateUtil
|
||||||
|
import info.nightscout.shared.utils.DateUtilImpl
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module(
|
@Module(
|
||||||
|
@ -23,4 +31,20 @@ open class SharedImplModule {
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideL(sp: SP): L = LImpl(sp)
|
fun provideL(sp: SP): L = LImpl(sp)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDateUtil(context: Context): DateUtil = DateUtilImpl(context)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideAAPSLogger(l: L): AAPSLogger = AAPSLoggerProduction(l)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRxBus(aapsSchedulers: AapsSchedulers, aapsLogger: AAPSLogger): RxBus = RxBusImpl(aapsSchedulers, aapsLogger)
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
internal fun provideSchedulers(): AapsSchedulers = AapsSchedulersImpl()
|
||||||
}
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package info.nightscout.rx.logging
|
package info.nightscout.shared.impl.logging
|
||||||
|
|
||||||
import info.nightscout.rx.interfaces.L
|
import info.nightscout.rx.interfaces.L
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
/**
|
/**
|
|
@ -0,0 +1,16 @@
|
||||||
|
package info.nightscout.shared.impl.rx
|
||||||
|
|
||||||
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.core.Scheduler
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
class AapsSchedulersImpl : AapsSchedulers {
|
||||||
|
|
||||||
|
override val main: Scheduler = AndroidSchedulers.mainThread()
|
||||||
|
override val io: Scheduler = Schedulers.io()
|
||||||
|
override val cpu: Scheduler = Schedulers.computation()
|
||||||
|
override val newThread: Scheduler = Schedulers.newThread()
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package info.nightscout.shared.impl.rx.bus
|
||||||
|
|
||||||
|
import info.nightscout.annotations.OpenForTesting
|
||||||
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
import info.nightscout.rx.bus.RxBus
|
||||||
|
import info.nightscout.rx.events.Event
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
|
import io.reactivex.rxjava3.core.Observable
|
||||||
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@OpenForTesting
|
||||||
|
@Singleton
|
||||||
|
class RxBusImpl @Inject constructor(
|
||||||
|
val aapsSchedulers: AapsSchedulers,
|
||||||
|
val aapsLogger: AAPSLogger
|
||||||
|
) : RxBus {
|
||||||
|
|
||||||
|
private val publisher = PublishSubject.create<Event>()
|
||||||
|
|
||||||
|
override fun send(event: Event) {
|
||||||
|
aapsLogger.debug(LTag.EVENTS, "Sending $event")
|
||||||
|
publisher.onNext(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen should return an Observable and not the publisher
|
||||||
|
// Using ofType we filter only events that match that class type
|
||||||
|
override fun <T : Any> toObservable(eventType: Class<T>): Observable<T> =
|
||||||
|
publisher
|
||||||
|
.subscribeOn(aapsSchedulers.io)
|
||||||
|
.ofType(eventType)
|
||||||
|
}
|
|
@ -0,0 +1,470 @@
|
||||||
|
package info.nightscout.shared.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.collection.LongSparseArray
|
||||||
|
import info.nightscout.annotations.OpenForTesting
|
||||||
|
import info.nightscout.shared.R
|
||||||
|
import info.nightscout.shared.SafeParse
|
||||||
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
|
import org.apache.commons.lang3.time.DateUtils.isSameDay
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
import org.joda.time.format.DateTimeFormat
|
||||||
|
import org.joda.time.format.ISODateTimeFormat
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
import java.text.DecimalFormatSymbols
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.EnumSet
|
||||||
|
import java.util.GregorianCalendar
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import java.util.stream.Collectors
|
||||||
|
import javax.inject.Inject
|
||||||
|
import javax.inject.Singleton
|
||||||
|
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
|
||||||
|
* with TZ
|
||||||
|
*/
|
||||||
|
@OpenForTesting
|
||||||
|
@Singleton
|
||||||
|
class DateUtilImpl @Inject constructor(private val context: Context) : DateUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date format in iso.
|
||||||
|
*/
|
||||||
|
@Suppress("PrivatePropertyName", "SpellCheckingInspection")
|
||||||
|
private val FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes in an ISO date string of the following format:
|
||||||
|
* yyyy-mm-ddThh:mm:ss.ms+HoMo
|
||||||
|
*
|
||||||
|
* @param isoDateString the iso date string
|
||||||
|
* @return the date
|
||||||
|
*/
|
||||||
|
override fun fromISODateString(isoDateString: String): Long {
|
||||||
|
val parser = ISODateTimeFormat.dateTimeParser()
|
||||||
|
val dateTime = DateTime.parse(isoDateString, parser)
|
||||||
|
return dateTime.toDate().time
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render date
|
||||||
|
*
|
||||||
|
* @param date the date obj
|
||||||
|
* @return the iso-formatted date string
|
||||||
|
*/
|
||||||
|
override fun toISOString(date: Long): String {
|
||||||
|
val f: DateFormat = SimpleDateFormat(FORMAT_DATE_ISO_OUT, Locale.getDefault())
|
||||||
|
f.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
return f.format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
override fun toISOAsUTC(timestamp: Long): String {
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'0000Z'", Locale.US)
|
||||||
|
format.timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
return format.format(timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SpellCheckingInspection")
|
||||||
|
override fun toISONoZone(timestamp: Long): String {
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
|
||||||
|
format.timeZone = TimeZone.getDefault()
|
||||||
|
return format.format(timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun secondsOfTheDayToMilliseconds(seconds: Int): Long {
|
||||||
|
val calendar: Calendar = GregorianCalendar()
|
||||||
|
calendar[Calendar.MONTH] = 0 // Set january to be sure we miss DST changing
|
||||||
|
calendar[Calendar.HOUR_OF_DAY] = seconds / 60 / 60
|
||||||
|
calendar[Calendar.MINUTE] = seconds / 60 % 60
|
||||||
|
calendar[Calendar.SECOND] = 0
|
||||||
|
return calendar.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toSeconds(hhColonMm: String): Int {
|
||||||
|
val p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)")
|
||||||
|
val m = p.matcher(hhColonMm)
|
||||||
|
var retVal = 0
|
||||||
|
if (m.find()) {
|
||||||
|
retVal = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60
|
||||||
|
if ((m.group(3) == " a.m." || m.group(3) == " AM" || m.group(3) == "AM") && m.group(1) == "12") retVal -= 12 * 60 * 60
|
||||||
|
if ((m.group(3) == " p.m." || m.group(3) == " PM" || m.group(3) == "PM") && m.group(1) != "12") retVal += 12 * 60 * 60
|
||||||
|
}
|
||||||
|
return retVal
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dateString(mills: Long): String {
|
||||||
|
val df = DateFormat.getDateInstance(DateFormat.SHORT)
|
||||||
|
return df.format(mills)
|
||||||
|
}
|
||||||
|
|
||||||
|
override 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dateStringShort(mills: Long): String {
|
||||||
|
var format = "MM/dd"
|
||||||
|
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
||||||
|
format = "dd/MM"
|
||||||
|
}
|
||||||
|
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun timeString(): String = timeString(now())
|
||||||
|
override fun timeString(mills: Long): String {
|
||||||
|
var format = "hh:mma"
|
||||||
|
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
||||||
|
format = "HH:mm"
|
||||||
|
}
|
||||||
|
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun secondString(): String = secondString(now())
|
||||||
|
override fun secondString(mills: Long): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern("ss"))
|
||||||
|
|
||||||
|
override fun minuteString(): String = minuteString(now())
|
||||||
|
override fun minuteString(mills: Long): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern("mm"))
|
||||||
|
|
||||||
|
override fun hourString(): String = hourString(now())
|
||||||
|
override fun hourString(mills: Long): String {
|
||||||
|
var format = "hh"
|
||||||
|
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
||||||
|
format = "HH"
|
||||||
|
}
|
||||||
|
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun amPm(): String = amPm(now())
|
||||||
|
override fun amPm(mills: Long): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern("a"))
|
||||||
|
|
||||||
|
override fun dayNameString(format: String): String = dayNameString(now(), format)
|
||||||
|
override fun dayNameString(mills: Long, format: String): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
|
||||||
|
override fun dayString(): String = dayString(now())
|
||||||
|
override fun dayString(mills: Long): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern("dd"))
|
||||||
|
|
||||||
|
override fun monthString(format: String): String = monthString(now(), format)
|
||||||
|
override fun monthString(mills: Long, format: String): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
|
||||||
|
override fun weekString(): String = weekString(now())
|
||||||
|
override fun weekString(mills: Long): String =
|
||||||
|
DateTime(mills).toString(DateTimeFormat.forPattern("ww"))
|
||||||
|
|
||||||
|
override fun timeStringWithSeconds(mills: Long): String {
|
||||||
|
var format = "hh:mm:ssa"
|
||||||
|
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
||||||
|
format = "HH:mm:ss"
|
||||||
|
}
|
||||||
|
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dateAndTimeRangeString(start: Long, end: Long): String {
|
||||||
|
return dateAndTimeString(start) + " - " + timeString(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun timeRangeString(start: Long, end: Long): String {
|
||||||
|
return timeString(start) + " - " + timeString(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dateAndTimeString(mills: Long): String {
|
||||||
|
return if (mills == 0L) "" else dateString(mills) + " " + timeString(mills)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dateAndTimeAndSecondsString(mills: Long): String {
|
||||||
|
return if (mills == 0L) "" else dateString(mills) + " " + timeStringWithSeconds(mills)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun minAgo(rh: ResourceHelper, time: Long?): String {
|
||||||
|
if (time == null) return ""
|
||||||
|
val minutes = ((now() - time) / 1000 / 60).toInt()
|
||||||
|
return rh.gs(R.string.minago, minutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun minAgoShort(time: Long?): String {
|
||||||
|
if (time == null) return ""
|
||||||
|
val minutes = ((time - now()) / 1000 / 60).toInt()
|
||||||
|
return (if (minutes > 0) "+" else "") + minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun minAgoLong(rh: ResourceHelper, time: Long?): String {
|
||||||
|
if (time == null) return ""
|
||||||
|
val minutes = ((now() - time) / 1000 / 60).toInt()
|
||||||
|
return rh.gs(R.string.minago_long, minutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hourAgo(time: Long, rh: ResourceHelper): String {
|
||||||
|
val hours = (now() - time) / 1000.0 / 60 / 60
|
||||||
|
return rh.gs(R.string.hoursago, hours)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dayAgo(time: Long, rh: ResourceHelper, round: Boolean): String {
|
||||||
|
var days = (now() - time) / 1000.0 / 60 / 60 / 24
|
||||||
|
if (round) {
|
||||||
|
return if (now() > time) {
|
||||||
|
days = ceil(days)
|
||||||
|
rh.gs(R.string.days_ago_round, days)
|
||||||
|
} else {
|
||||||
|
days = floor(days)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
override 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
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun timeStringFromSeconds(seconds: Int): String {
|
||||||
|
val cached = timeStrings[seconds.toLong()]
|
||||||
|
if (cached != null) return cached
|
||||||
|
val t = timeString(secondsOfTheDayToMilliseconds(seconds))
|
||||||
|
timeStrings.put(seconds.toLong(), t)
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun timeFrameString(timeInMillis: Long, rh: ResourceHelper): String {
|
||||||
|
var remainingTimeMinutes = timeInMillis / (1000 * 60)
|
||||||
|
val remainingTimeHours = remainingTimeMinutes / 60
|
||||||
|
remainingTimeMinutes %= 60
|
||||||
|
return "(" + (if (remainingTimeHours > 0) remainingTimeHours.toString() + rh.gs(R.string.shorthour) + " " else "") + remainingTimeMinutes + "')"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sinceString(timestamp: Long, rh: ResourceHelper): String {
|
||||||
|
return timeFrameString(System.currentTimeMillis() - timestamp, rh)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun untilString(timestamp: Long, rh: ResourceHelper): String {
|
||||||
|
return timeFrameString(timestamp - System.currentTimeMillis(), rh)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun now(): Long {
|
||||||
|
return System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nowWithoutMilliseconds(): Long {
|
||||||
|
var n = System.currentTimeMillis()
|
||||||
|
n -= n % 1000
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isOlderThan(date: Long, minutes: Long): Boolean {
|
||||||
|
val diff = now() - date
|
||||||
|
return diff > T.mins(minutes).msecs()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTimeZoneOffsetMs(): Long {
|
||||||
|
return GregorianCalendar().timeZone.rawOffset.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTimeZoneOffsetMinutes(timestamp: Long): Int {
|
||||||
|
return TimeZone.getDefault().getOffset(timestamp) / 60000
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isSameDay(timestamp1: Long, timestamp2: Long) = isSameDay(Date(timestamp1), Date(timestamp2))
|
||||||
|
|
||||||
|
override fun isSameDayGroup(timestamp1: Long, timestamp2: Long): Boolean {
|
||||||
|
val now = now()
|
||||||
|
if (now in (timestamp1 + 1) until timestamp2 || now in (timestamp2 + 1) until timestamp1)
|
||||||
|
return false
|
||||||
|
return isSameDay(Date(timestamp1), Date(timestamp2))
|
||||||
|
}
|
||||||
|
|
||||||
|
//Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
|
||||||
|
override fun computeDiff(date1: Long, date2: Long): Map<TimeUnit, Long> {
|
||||||
|
val units: MutableList<TimeUnit> = ArrayList(EnumSet.allOf(TimeUnit::class.java))
|
||||||
|
units.reverse()
|
||||||
|
val result: MutableMap<TimeUnit, Long> = LinkedHashMap()
|
||||||
|
var millisecondsRest = date2 - date1
|
||||||
|
for (unit in units) {
|
||||||
|
val diff = unit.convert(millisecondsRest, TimeUnit.MILLISECONDS)
|
||||||
|
val diffInMillisecondsForUnit = unit.toMillis(diff)
|
||||||
|
millisecondsRest -= diffInMillisecondsForUnit
|
||||||
|
result[unit] = diff
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun age(milliseconds: Long, useShortText: Boolean, rh: ResourceHelper): String {
|
||||||
|
val diff = computeDiff(0L, milliseconds)
|
||||||
|
var days = " " + rh.gs(R.string.days) + " "
|
||||||
|
var hours = " " + rh.gs(R.string.hours) + " "
|
||||||
|
var minutes = " " + rh.gs(R.string.unit_minutes) + " "
|
||||||
|
if (useShortText) {
|
||||||
|
days = rh.gs(R.string.shortday)
|
||||||
|
hours = rh.gs(R.string.shorthour)
|
||||||
|
minutes = rh.gs(R.string.shortminute)
|
||||||
|
}
|
||||||
|
var result = ""
|
||||||
|
if (diff.getOrDefault(TimeUnit.DAYS, -1) > 0) result += diff[TimeUnit.DAYS].toString() + days
|
||||||
|
if (diff.getOrDefault(TimeUnit.HOURS, -1) > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
||||||
|
if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun niceTimeScalar(time: Long, rh: ResourceHelper): String {
|
||||||
|
var t = time
|
||||||
|
var unit = rh.gs(R.string.unit_second)
|
||||||
|
t /= 1000
|
||||||
|
if (t != 1L) unit = rh.gs(R.string.unit_seconds)
|
||||||
|
if (t > 59) {
|
||||||
|
unit = rh.gs(R.string.unit_minute)
|
||||||
|
t /= 60
|
||||||
|
if (t != 1L) unit = rh.gs(R.string.unit_minutes)
|
||||||
|
if (t > 59) {
|
||||||
|
unit = rh.gs(R.string.unit_hour)
|
||||||
|
t /= 60
|
||||||
|
if (t != 1L) unit = rh.gs(R.string.unit_hours)
|
||||||
|
if (t > 24) {
|
||||||
|
unit = rh.gs(R.string.unit_day)
|
||||||
|
t /= 24
|
||||||
|
if (t != 1L) unit = rh.gs(R.string.unit_days)
|
||||||
|
if (t > 28) {
|
||||||
|
unit = rh.gs(R.string.unit_week)
|
||||||
|
t /= 7
|
||||||
|
@Suppress("KotlinConstantConditions")
|
||||||
|
if (t != 1L) unit = rh.gs(R.string.unit_weeks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character
|
||||||
|
return qs(t.toDouble(), 0) + " " + unit
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun qs(x: Double, numDigits: Int): String {
|
||||||
|
var digits = numDigits
|
||||||
|
if (digits == -1) {
|
||||||
|
digits = 0
|
||||||
|
if ((x.toInt() % x == 0.0)) {
|
||||||
|
digits++
|
||||||
|
if ((x.toInt() * 10 / 10).toDouble() != x) {
|
||||||
|
digits++
|
||||||
|
if ((x.toInt() * 100 / 100).toDouble() != x) digits++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dfs == null) {
|
||||||
|
val localDfs = DecimalFormatSymbols()
|
||||||
|
localDfs.decimalSeparator = '.'
|
||||||
|
dfs = localDfs // avoid race condition
|
||||||
|
}
|
||||||
|
val thisDf: DecimalFormat?
|
||||||
|
// use singleton if on ui thread otherwise allocate new as DecimalFormat is not thread safe
|
||||||
|
if (Thread.currentThread().id == 1L) {
|
||||||
|
if (df == null) {
|
||||||
|
val localDf = DecimalFormat("#", dfs)
|
||||||
|
localDf.minimumIntegerDigits = 1
|
||||||
|
df = localDf // avoid race condition
|
||||||
|
}
|
||||||
|
thisDf = df
|
||||||
|
} else {
|
||||||
|
thisDf = DecimalFormat("#", dfs)
|
||||||
|
}
|
||||||
|
thisDf?.maximumFractionDigits = digits
|
||||||
|
return thisDf?.format(x) ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun formatHHMM(timeAsSeconds: Int): String {
|
||||||
|
val hour = timeAsSeconds / 60 / 60
|
||||||
|
val minutes = (timeAsSeconds - hour * 60 * 60) / 60
|
||||||
|
val df = DecimalFormat("00")
|
||||||
|
return df.format(hour.toLong()) + ":" + df.format(minutes.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
override fun timeZoneByOffset(offsetInMilliseconds: Long): TimeZone =
|
||||||
|
TimeZone.getTimeZone(
|
||||||
|
if (offsetInMilliseconds == 0L) ZoneId.of("UTC")
|
||||||
|
else ZoneId.getAvailableZoneIds()
|
||||||
|
.stream()
|
||||||
|
.map(ZoneId::of)
|
||||||
|
.filter { z -> z.rules.getOffset(Instant.now()).totalSeconds == ZoneOffset.ofHours((offsetInMilliseconds / 1000 / 3600).toInt()).totalSeconds }
|
||||||
|
.collect(Collectors.toList())
|
||||||
|
.firstOrNull() ?: ZoneId.of("UTC")
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun timeStampToUtcDateMillis(timestamp: Long): Long {
|
||||||
|
val current = Calendar.getInstance().apply { timeInMillis = timestamp }
|
||||||
|
return Calendar.getInstance().apply {
|
||||||
|
set(Calendar.YEAR, current[Calendar.YEAR])
|
||||||
|
set(Calendar.MONTH, current[Calendar.MONTH])
|
||||||
|
set(Calendar.DAY_OF_MONTH, current[Calendar.DAY_OF_MONTH])
|
||||||
|
}.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mergeUtcDateToTimestamp(timestamp: Long, dateUtcMillis: Long): Long {
|
||||||
|
val selected = Calendar.getInstance().apply { timeInMillis = dateUtcMillis }
|
||||||
|
return Calendar.getInstance().apply {
|
||||||
|
timeInMillis = timestamp
|
||||||
|
set(Calendar.YEAR, selected[Calendar.YEAR])
|
||||||
|
set(Calendar.MONTH, selected[Calendar.MONTH])
|
||||||
|
set(Calendar.DAY_OF_MONTH, selected[Calendar.DAY_OF_MONTH])
|
||||||
|
}.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mergeHourMinuteToTimestamp(timestamp: Long, hour: Int, minute: Int, randomSecond: Boolean): Long {
|
||||||
|
return Calendar.getInstance().apply {
|
||||||
|
timeInMillis = timestamp
|
||||||
|
set(Calendar.HOUR_OF_DAY, hour)
|
||||||
|
set(Calendar.MINUTE, minute)
|
||||||
|
if (randomSecond) set(Calendar.SECOND, seconds++)
|
||||||
|
}.timeInMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private val timeStrings = LongSparseArray<String>()
|
||||||
|
private var seconds: Int = (SecureRandom().nextDouble() * 59.0).toInt()
|
||||||
|
|
||||||
|
// singletons to avoid repeated allocation
|
||||||
|
private var dfs: DecimalFormatSymbols? = null
|
||||||
|
private var df: DecimalFormat? = null
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:viewportWidth="24"
|
android:viewportWidth="24"
|
||||||
android:viewportHeight="24">
|
android:viewportHeight="24">
|
||||||
<path
|
<path
|
||||||
android:fillColor="#FF000000"
|
android:fillColor="#FF000000"
|
||||||
android:pathData="M0.103,0h24v24h-24z"/>
|
android:pathData="M0.103,0h24v24h-24z" />
|
||||||
</vector>
|
</vector>
|
|
@ -0,0 +1,306 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="400dp"
|
||||||
|
android:height="400dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M10.744,0.074L10.885,1.416"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M13.113,22.599L13.254,23.942"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9.504,0.27L9.784,1.591"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M14.214,22.425L14.495,23.745"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M8.29,0.595L8.708,1.88"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M15.291,22.136L15.708,23.42"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M7.118,1.046L7.667,2.279"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M16.332,21.737L16.881,22.97"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M4.945,2.3L5.739,3.392"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M18.26,20.623L19.053,21.716"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M3.969,3.091L4.873,4.094"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19.126,19.922L20.029,20.925"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M3.081,3.979L4.084,4.882"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19.914,19.133L20.917,20.037"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M2.291,4.955L3.383,5.749"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M20.616,18.267L21.708,19.061"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M1.036,7.128L2.27,7.677"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M21.729,16.339L22.962,16.888"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.586,8.3L1.871,8.718"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.128,15.298L23.412,15.715"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.261,9.514L1.582,9.794"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.416,14.221L23.737,14.502"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.065,10.754L1.408,10.895"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.591,13.12L23.934,13.261"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.065,13.263L1.408,13.122"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.591,10.894L23.933,10.753"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.262,14.503L1.582,14.223"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.416,9.793L23.737,9.512"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0.587,15.717L1.871,15.299"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M22.128,8.716L23.412,8.299"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M1.037,16.889L2.271,16.34"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M21.728,7.676L22.962,7.126"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M2.291,19.062L3.384,18.268"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M20.615,5.747L21.707,4.954"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M3.082,20.038L4.085,19.134"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19.913,4.881L20.917,3.978"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M3.97,20.926L4.874,19.923"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19.125,4.093L20.028,3.09"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M4.946,21.716L5.74,20.624"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M18.258,3.392L19.052,2.299"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M7.119,22.971L7.668,21.737"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M16.33,2.278L16.879,1.045"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M8.292,23.421L8.709,22.137"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M15.29,1.879L15.707,0.595"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9.505,23.746L9.786,22.425"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M14.213,1.591L14.494,0.27"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M10.746,23.942L10.887,22.599"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M13.112,1.416L13.253,0.073"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,0.008L11.999,2.708"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,21.307L11.999,24.008"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M23.999,12L21.298,12"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M2.699,12L-0.001,12"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M5.999,1.616L7.349,3.954"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M16.648,20.061L17.999,22.4"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M22.387,6.001L20.048,7.351"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M3.941,16.651L1.602,18.001"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M1.606,6.008L3.945,7.358"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M20.052,16.658L22.391,18.008"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M17.992,1.612L16.642,3.95"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M7.342,20.057L5.992,22.396"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="400dp"
|
||||||
|
android:height="400dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,4.906c-0.104,0 -0.188,0.084 -0.188,0.188V12c0,0.104 0.084,0.188 0.188,0.188c0.104,0 0.188,-0.084 0.188,-0.188V5.094C12.186,4.99 12.102,4.906 11.999,4.906zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="400dp"
|
||||||
|
android:height="400dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,1.406c-0.104,0 -0.188,0.084 -0.188,0.188V12c0,0.104 0.084,0.188 0.188,0.188c0.104,0 0.188,-0.084 0.188,-0.188V1.594C12.186,1.49 12.102,1.406 11.999,1.406zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="400dp"
|
||||||
|
android:height="400dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FF1313"
|
||||||
|
android:pathData="M12.198,11.462v-0.237c0,-0.077 -0.05,-0.131 -0.114,-0.164V0.508c0,-0.047 -0.038,-0.086 -0.086,-0.086c-0.047,0 -0.086,0.038 -0.086,0.086v10.553c-0.063,0.033 -0.114,0.087 -0.114,0.164v0.238c-0.219,0.082 -0.376,0.29 -0.376,0.537s0.157,0.455 0.376,0.537v0.92c0,0.11 0.089,0.2 0.2,0.2s0.2,-0.089 0.2,-0.2v-0.919c0.221,-0.081 0.381,-0.289 0.381,-0.538S12.419,11.543 12.198,11.462zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,66 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="400dp"
|
||||||
|
android:height="400dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,0.008L11.999,2.708"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M11.999,21.307L11.999,24.008"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M23.999,12L21.298,12"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M2.699,12L-0.001,12"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M5.999,1.616L7.349,3.954"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M16.648,20.061L17.999,22.4"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M22.387,6.001L20.048,7.351"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M3.941,16.651L1.602,18.001"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M1.606,6.008L3.945,7.358"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M20.052,16.658L22.391,18.008"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M17.992,1.612L16.642,3.95"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M7.342,20.057L5.992,22.396"
|
||||||
|
android:strokeWidth="0.1417"
|
||||||
|
android:strokeColor="#FFFFFF" />
|
||||||
|
</vector>
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
@ -14,16 +14,18 @@ apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace 'info.nightscout.sharedtests'
|
namespace 'info.nightscout.sharedtests'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':database:entities')
|
implementation project(':database:entities')
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
implementation project(':core:interfaces')
|
implementation project(':core:interfaces')
|
||||||
implementation project(':core:main')
|
implementation project(':core:main')
|
||||||
implementation project(':core:utils')
|
implementation project(':core:utils')
|
||||||
implementation project(':implementation')
|
implementation project(':implementation')
|
||||||
|
|
||||||
|
|
||||||
api "org.mockito:mockito-junit-jupiter:$mockito_version"
|
api "org.mockito:mockito-junit-jupiter:$mockito_version"
|
||||||
api "org.mockito.kotlin:mockito-kotlin:5.1.0"
|
api "org.mockito.kotlin:mockito-kotlin:5.1.0"
|
||||||
api "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
api "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
package info.nightscout.rx.logging
|
package info.nightscout.sharedtests
|
||||||
|
|
||||||
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.rx.logging.LTag
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by adrian on 2019-12-27.
|
* Created by adrian on 2019-12-27.
|
|
@ -2,8 +2,7 @@ package info.nightscout.sharedtests
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.TestAapsSchedulers
|
import info.nightscout.sharedtests.rx.TestAapsSchedulers
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
import org.mockito.ArgumentMatcher
|
import org.mockito.ArgumentMatcher
|
||||||
|
|
|
@ -19,11 +19,11 @@ import info.nightscout.interfaces.profile.ProfileFunction
|
||||||
import info.nightscout.interfaces.profile.ProfileStore
|
import info.nightscout.interfaces.profile.ProfileStore
|
||||||
import info.nightscout.interfaces.utils.DecimalFormatter
|
import info.nightscout.interfaces.utils.DecimalFormatter
|
||||||
import info.nightscout.interfaces.utils.HardLimits
|
import info.nightscout.interfaces.utils.HardLimits
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.shared.impl.rx.bus.RxBusImpl
|
||||||
import info.nightscout.shared.interfaces.ProfileUtil
|
import info.nightscout.shared.interfaces.ProfileUtil
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtilImpl
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.mockito.ArgumentMatchers.anyDouble
|
import org.mockito.ArgumentMatchers.anyDouble
|
||||||
|
@ -45,11 +45,11 @@ open class TestBaseWithProfile : TestBase() {
|
||||||
@Mock lateinit var context: Context
|
@Mock lateinit var context: Context
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
|
||||||
lateinit var dateUtil: DateUtil
|
lateinit var dateUtil: DateUtilImpl
|
||||||
lateinit var profileUtil: ProfileUtil
|
lateinit var profileUtil: ProfileUtil
|
||||||
lateinit var decimalFormatter: DecimalFormatter
|
lateinit var decimalFormatter: DecimalFormatter
|
||||||
lateinit var hardLimits: HardLimits
|
lateinit var hardLimits: HardLimits
|
||||||
val rxBus = RxBus(aapsSchedulers, aapsLogger)
|
val rxBus = RxBusImpl(aapsSchedulers, aapsLogger)
|
||||||
|
|
||||||
val profileInjector = HasAndroidInjector {
|
val profileInjector = HasAndroidInjector {
|
||||||
AndroidInjector {
|
AndroidInjector {
|
||||||
|
@ -82,7 +82,7 @@ open class TestBaseWithProfile : TestBase() {
|
||||||
invalidProfileJSON = "{\"dia\":\"1\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
invalidProfileJSON = "{\"dia\":\"1\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
|
||||||
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
|
||||||
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
|
||||||
dateUtil = Mockito.spy(DateUtil(context))
|
dateUtil = Mockito.spy(DateUtilImpl(context))
|
||||||
decimalFormatter = DecimalFormatterImpl(rh)
|
decimalFormatter = DecimalFormatterImpl(rh)
|
||||||
profileUtil = ProfileUtilImpl(sp, decimalFormatter)
|
profileUtil = ProfileUtilImpl(sp, decimalFormatter)
|
||||||
testPumpPlugin = TestPumpPlugin(profileInjector)
|
testPumpPlugin = TestPumpPlugin(profileInjector)
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package info.nightscout.sharedtests.rx
|
||||||
|
|
||||||
|
import info.nightscout.rx.AapsSchedulers
|
||||||
|
import io.reactivex.rxjava3.core.Scheduler
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by adrian on 12.04.20.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TestAapsSchedulers : AapsSchedulers {
|
||||||
|
|
||||||
|
override val main: Scheduler = Schedulers.trampoline()
|
||||||
|
override val io: Scheduler = Schedulers.trampoline()
|
||||||
|
override val cpu: Scheduler = Schedulers.trampoline()
|
||||||
|
override val newThread: Scheduler = Schedulers.trampoline()
|
||||||
|
}
|
|
@ -1,30 +1,15 @@
|
||||||
package info.nightscout.rx
|
package info.nightscout.rx
|
||||||
|
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
|
||||||
import io.reactivex.rxjava3.core.Scheduler
|
import io.reactivex.rxjava3.core.Scheduler
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by adrian on 12.04.20.
|
* Created by adrian on 12.04.20.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
interface AapsSchedulers {
|
interface AapsSchedulers {
|
||||||
|
|
||||||
val main: Scheduler
|
val main: Scheduler
|
||||||
val io: Scheduler
|
val io: Scheduler
|
||||||
val cpu: Scheduler
|
val cpu: Scheduler
|
||||||
val newThread: Scheduler
|
val newThread: Scheduler
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultAapsSchedulers : AapsSchedulers {
|
|
||||||
override val main: Scheduler = AndroidSchedulers.mainThread()
|
|
||||||
override val io: Scheduler = Schedulers.io()
|
|
||||||
override val cpu: Scheduler = Schedulers.computation()
|
|
||||||
override val newThread: Scheduler = Schedulers.newThread()
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestAapsSchedulers : AapsSchedulers {
|
|
||||||
override val main: Scheduler = Schedulers.trampoline()
|
|
||||||
override val io: Scheduler = Schedulers.trampoline()
|
|
||||||
override val cpu: Scheduler = Schedulers.trampoline()
|
|
||||||
override val newThread: Scheduler = Schedulers.trampoline()
|
|
||||||
}
|
}
|
|
@ -1,33 +1,13 @@
|
||||||
package info.nightscout.rx.bus
|
package info.nightscout.rx.bus
|
||||||
|
|
||||||
import info.nightscout.annotations.OpenForTesting
|
|
||||||
import info.nightscout.rx.AapsSchedulers
|
|
||||||
import info.nightscout.rx.events.Event
|
import info.nightscout.rx.events.Event
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
|
||||||
import info.nightscout.rx.logging.LTag
|
|
||||||
import io.reactivex.rxjava3.core.Observable
|
import io.reactivex.rxjava3.core.Observable
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@OpenForTesting
|
interface RxBus {
|
||||||
@Singleton
|
|
||||||
class RxBus @Inject constructor(
|
|
||||||
val aapsSchedulers: AapsSchedulers,
|
|
||||||
val aapsLogger: AAPSLogger
|
|
||||||
) {
|
|
||||||
|
|
||||||
private val publisher = PublishSubject.create<Event>()
|
fun send(event: Event)
|
||||||
|
|
||||||
fun send(event: Event) {
|
|
||||||
aapsLogger.debug(LTag.EVENTS, "Sending $event")
|
|
||||||
publisher.onNext(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Listen should return an Observable and not the publisher
|
// Listen should return an Observable and not the publisher
|
||||||
// Using ofType we filter only events that match that class type
|
// Using ofType we filter only events that match that class type
|
||||||
fun <T : Any> toObservable(eventType: Class<T>): Observable<T> =
|
fun <T : Any> toObservable(eventType: Class<T>): Observable<T>
|
||||||
publisher
|
|
||||||
.subscribeOn(aapsSchedulers.io)
|
|
||||||
.ofType(eventType)
|
|
||||||
}
|
}
|
|
@ -1,25 +0,0 @@
|
||||||
package info.nightscout.rx.di
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
import dagger.Provides
|
|
||||||
import info.nightscout.rx.AapsSchedulers
|
|
||||||
import info.nightscout.rx.DefaultAapsSchedulers
|
|
||||||
import info.nightscout.rx.interfaces.L
|
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
|
||||||
import info.nightscout.rx.logging.AAPSLoggerProduction
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Module(
|
|
||||||
includes = [
|
|
||||||
]
|
|
||||||
)
|
|
||||||
open class RxModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
internal fun provideSchedulers(): AapsSchedulers = DefaultAapsSchedulers()
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
fun provideAAPSLogger(l: L): AAPSLogger = AAPSLoggerProduction(l)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
package info.nightscout.shared.di
|
|
||||||
|
|
||||||
import dagger.Module
|
|
||||||
|
|
||||||
@Module(
|
|
||||||
includes = [
|
|
||||||
]
|
|
||||||
)
|
|
||||||
open class SharedModule
|
|
|
@ -1,52 +1,16 @@
|
||||||
package info.nightscout.shared.utils
|
package info.nightscout.shared.utils
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.collection.LongSparseArray
|
|
||||||
import info.nightscout.annotations.OpenForTesting
|
|
||||||
import info.nightscout.shared.R
|
|
||||||
import info.nightscout.shared.SafeParse
|
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import org.apache.commons.lang3.time.DateUtils.isSameDay
|
|
||||||
import org.joda.time.DateTime
|
|
||||||
import org.joda.time.format.DateTimeFormat
|
|
||||||
import org.joda.time.format.ISODateTimeFormat
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.DecimalFormat
|
|
||||||
import java.text.DecimalFormatSymbols
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.time.Instant
|
|
||||||
import java.time.ZoneId
|
|
||||||
import java.time.ZoneOffset
|
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.EnumSet
|
|
||||||
import java.util.GregorianCalendar
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.regex.Pattern
|
|
||||||
import java.util.stream.Collectors
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
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
|
* The Class DateUtil. A simple wrapper around SimpleDateFormat to ease the handling of iso date string <-> date obj
|
||||||
* with TZ
|
* with TZ
|
||||||
*/
|
*/
|
||||||
@OpenForTesting
|
interface DateUtil {
|
||||||
@Singleton
|
|
||||||
class DateUtil @Inject constructor(private val context: Context) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The date format in iso.
|
|
||||||
*/
|
|
||||||
@Suppress("PrivatePropertyName", "SpellCheckingInspection")
|
|
||||||
private val FORMAT_DATE_ISO_OUT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes in an ISO date string of the following format:
|
* Takes in an ISO date string of the following format:
|
||||||
|
@ -55,11 +19,7 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
* @param isoDateString the iso date string
|
* @param isoDateString the iso date string
|
||||||
* @return the date
|
* @return the date
|
||||||
*/
|
*/
|
||||||
fun fromISODateString(isoDateString: String): Long {
|
fun fromISODateString(isoDateString: String): Long
|
||||||
val parser = ISODateTimeFormat.dateTimeParser()
|
|
||||||
val dateTime = DateTime.parse(isoDateString, parser)
|
|
||||||
return dateTime.toDate().time
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render date
|
* Render date
|
||||||
|
@ -67,404 +27,66 @@ class DateUtil @Inject constructor(private val context: Context) {
|
||||||
* @param date the date obj
|
* @param date the date obj
|
||||||
* @return the iso-formatted date string
|
* @return the iso-formatted date string
|
||||||
*/
|
*/
|
||||||
fun toISOString(date: Long): String {
|
fun toISOString(date: Long): String
|
||||||
val f: DateFormat = SimpleDateFormat(FORMAT_DATE_ISO_OUT, Locale.getDefault())
|
fun toISOAsUTC(timestamp: Long): String
|
||||||
f.timeZone = TimeZone.getTimeZone("UTC")
|
fun toISONoZone(timestamp: Long): String
|
||||||
return f.format(date)
|
fun secondsOfTheDayToMilliseconds(seconds: Int): Long
|
||||||
}
|
fun toSeconds(hhColonMm: String): Int
|
||||||
|
fun dateString(mills: Long): String
|
||||||
@Suppress("SpellCheckingInspection")
|
fun dateStringRelative(mills: Long, rh: ResourceHelper): String
|
||||||
fun toISOAsUTC(timestamp: Long): String {
|
fun dateStringShort(mills: Long): String
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'0000Z'", Locale.US)
|
fun timeString(): String
|
||||||
format.timeZone = TimeZone.getTimeZone("UTC")
|
fun timeString(mills: Long): String
|
||||||
return format.format(timestamp)
|
fun secondString(): String
|
||||||
}
|
fun secondString(mills: Long): String
|
||||||
|
fun minuteString(): String
|
||||||
@Suppress("SpellCheckingInspection")
|
fun minuteString(mills: Long): String
|
||||||
fun toISONoZone(timestamp: Long): String {
|
fun hourString(): String
|
||||||
val format = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US)
|
fun hourString(mills: Long): String
|
||||||
format.timeZone = TimeZone.getDefault()
|
fun amPm(): String
|
||||||
return format.format(timestamp)
|
fun amPm(mills: Long): String
|
||||||
}
|
fun dayNameString(format: String = "E"): String
|
||||||
|
fun dayNameString(mills: Long, format: String = "E"): String
|
||||||
fun secondsOfTheDayToMilliseconds(seconds: Int): Long {
|
|
||||||
val calendar: Calendar = GregorianCalendar()
|
|
||||||
calendar[Calendar.MONTH] = 0 // Set january to be sure we miss DST changing
|
|
||||||
calendar[Calendar.HOUR_OF_DAY] = seconds / 60 / 60
|
|
||||||
calendar[Calendar.MINUTE] = seconds / 60 % 60
|
|
||||||
calendar[Calendar.SECOND] = 0
|
|
||||||
return calendar.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toSeconds(hhColonMm: String): Int {
|
|
||||||
val p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM| PM|AM|PM|)")
|
|
||||||
val m = p.matcher(hhColonMm)
|
|
||||||
var retVal = 0
|
|
||||||
if (m.find()) {
|
|
||||||
retVal = SafeParse.stringToInt(m.group(1)) * 60 * 60 + SafeParse.stringToInt(m.group(2)) * 60
|
|
||||||
if ((m.group(3) == " a.m." || m.group(3) == " AM" || m.group(3) == "AM") && m.group(1) == "12") retVal -= 12 * 60 * 60
|
|
||||||
if ((m.group(3) == " p.m." || m.group(3) == " PM" || m.group(3) == "PM") && m.group(1) != "12") retVal += 12 * 60 * 60
|
|
||||||
}
|
|
||||||
return retVal
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dateString(mills: Long): String {
|
|
||||||
val df = DateFormat.getDateInstance(DateFormat.SHORT)
|
|
||||||
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)) {
|
|
||||||
format = "dd/MM"
|
|
||||||
}
|
|
||||||
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun timeString(): String = timeString(now())
|
|
||||||
fun timeString(mills: Long): String {
|
|
||||||
var format = "hh:mma"
|
|
||||||
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
|
||||||
format = "HH:mm"
|
|
||||||
}
|
|
||||||
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun secondString(): String = secondString(now())
|
|
||||||
fun secondString(mills: Long): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern("ss"))
|
|
||||||
|
|
||||||
fun minuteString(): String = minuteString(now())
|
|
||||||
fun minuteString(mills: Long): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern("mm"))
|
|
||||||
|
|
||||||
fun hourString(): String = hourString(now())
|
|
||||||
fun hourString(mills: Long): String {
|
|
||||||
var format = "hh"
|
|
||||||
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
|
||||||
format = "HH"
|
|
||||||
}
|
|
||||||
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun amPm(): String = amPm(now())
|
|
||||||
fun amPm(mills: Long): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern("a"))
|
|
||||||
|
|
||||||
fun dayNameString(format: String = "E"): String = dayNameString(now(), format)
|
|
||||||
fun dayNameString(mills: Long, format: String = "E"): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
|
|
||||||
fun dayString(): String = dayString(now())
|
fun dayString(): String = dayString(now())
|
||||||
fun dayString(mills: Long): String =
|
fun dayString(mills: Long): String
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern("dd"))
|
fun monthString(format: String = "MMM"): String
|
||||||
|
fun monthString(mills: Long, format: String = "MMM"): String
|
||||||
|
fun weekString(): String
|
||||||
|
fun weekString(mills: Long): String
|
||||||
|
fun timeStringWithSeconds(mills: Long): String
|
||||||
|
fun dateAndTimeRangeString(start: Long, end: Long): String
|
||||||
|
fun timeRangeString(start: Long, end: Long): String
|
||||||
|
fun dateAndTimeString(mills: Long): String
|
||||||
|
fun dateAndTimeAndSecondsString(mills: Long): String
|
||||||
|
fun minAgo(rh: ResourceHelper, time: Long?): String
|
||||||
|
fun minAgoShort(time: Long?): String
|
||||||
|
fun minAgoLong(rh: ResourceHelper, time: Long?): String
|
||||||
|
fun hourAgo(time: Long, rh: ResourceHelper): String
|
||||||
|
fun dayAgo(time: Long, rh: ResourceHelper, round: Boolean = false): String
|
||||||
|
fun beginOfDay(mills: Long): Long
|
||||||
|
fun timeStringFromSeconds(seconds: Int): String
|
||||||
|
fun timeFrameString(timeInMillis: Long, rh: ResourceHelper): String
|
||||||
|
fun sinceString(timestamp: Long, rh: ResourceHelper): String
|
||||||
|
fun untilString(timestamp: Long, rh: ResourceHelper): String
|
||||||
|
fun now(): Long
|
||||||
|
fun nowWithoutMilliseconds(): Long
|
||||||
|
fun isOlderThan(date: Long, minutes: Long): Boolean
|
||||||
|
fun getTimeZoneOffsetMs(): Long
|
||||||
|
fun getTimeZoneOffsetMinutes(timestamp: Long): Int
|
||||||
|
fun isSameDay(timestamp1: Long, timestamp2: Long): Boolean
|
||||||
|
|
||||||
fun monthString(format: String = "MMM"): String = monthString(now(), format)
|
fun isSameDayGroup(timestamp1: Long, timestamp2: Long): Boolean
|
||||||
fun monthString(mills: Long, format: String = "MMM"): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
|
|
||||||
fun weekString(): String = weekString(now())
|
|
||||||
fun weekString(mills: Long): String =
|
|
||||||
DateTime(mills).toString(DateTimeFormat.forPattern("ww"))
|
|
||||||
|
|
||||||
fun timeStringWithSeconds(mills: Long): String {
|
|
||||||
var format = "hh:mm:ssa"
|
|
||||||
if (android.text.format.DateFormat.is24HourFormat(context)) {
|
|
||||||
format = "HH:mm:ss"
|
|
||||||
}
|
|
||||||
return DateTime(mills).toString(DateTimeFormat.forPattern(format))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dateAndTimeRangeString(start: Long, end: Long): String {
|
|
||||||
return dateAndTimeString(start) + " - " + timeString(end)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun timeRangeString(start: Long, end: Long): String {
|
|
||||||
return timeString(start) + " - " + timeString(end)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dateAndTimeString(mills: Long): String {
|
|
||||||
return if (mills == 0L) "" else dateString(mills) + " " + timeString(mills)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dateAndTimeAndSecondsString(mills: Long): String {
|
|
||||||
return if (mills == 0L) "" else dateString(mills) + " " + timeStringWithSeconds(mills)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun minAgo(rh: ResourceHelper, time: Long?): String {
|
|
||||||
if (time == null) return ""
|
|
||||||
val minutes = ((now() - time) / 1000 / 60).toInt()
|
|
||||||
return rh.gs(R.string.minago, minutes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun minAgoShort(time: Long?): String {
|
|
||||||
if (time == null) return ""
|
|
||||||
val minutes = ((time - now()) / 1000 / 60).toInt()
|
|
||||||
return (if (minutes > 0) "+" else "") + minutes
|
|
||||||
}
|
|
||||||
|
|
||||||
fun minAgoLong(rh: ResourceHelper, time: Long?): String {
|
|
||||||
if (time == null) return ""
|
|
||||||
val minutes = ((now() - time) / 1000 / 60).toInt()
|
|
||||||
return rh.gs(R.string.minago_long, minutes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hourAgo(time: Long, rh: ResourceHelper): String {
|
|
||||||
val hours = (now() - time) / 1000.0 / 60 / 60
|
|
||||||
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) {
|
|
||||||
return if (now() > time) {
|
|
||||||
days = ceil(days)
|
|
||||||
rh.gs(R.string.days_ago_round, days)
|
|
||||||
} else {
|
|
||||||
days = floor(days)
|
|
||||||
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
|
|
||||||
val t = timeString(secondsOfTheDayToMilliseconds(seconds))
|
|
||||||
timeStrings.put(seconds.toLong(), t)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
fun timeFrameString(timeInMillis: Long, rh: ResourceHelper): String {
|
|
||||||
var remainingTimeMinutes = timeInMillis / (1000 * 60)
|
|
||||||
val remainingTimeHours = remainingTimeMinutes / 60
|
|
||||||
remainingTimeMinutes %= 60
|
|
||||||
return "(" + (if (remainingTimeHours > 0) remainingTimeHours.toString() + rh.gs(R.string.shorthour) + " " else "") + remainingTimeMinutes + "')"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun sinceString(timestamp: Long, rh: ResourceHelper): String {
|
|
||||||
return timeFrameString(System.currentTimeMillis() - timestamp, rh)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun untilString(timestamp: Long, rh: ResourceHelper): String {
|
|
||||||
return timeFrameString(timestamp - System.currentTimeMillis(), rh)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun now(): Long {
|
|
||||||
return System.currentTimeMillis()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun nowWithoutMilliseconds(): Long {
|
|
||||||
var n = System.currentTimeMillis()
|
|
||||||
n -= n % 1000
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isOlderThan(date: Long, minutes: Long): Boolean {
|
|
||||||
val diff = now() - date
|
|
||||||
return diff > T.mins(minutes).msecs()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTimeZoneOffsetMs(): Long {
|
|
||||||
return GregorianCalendar().timeZone.rawOffset.toLong()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTimeZoneOffsetMinutes(timestamp: Long): Int {
|
|
||||||
return TimeZone.getDefault().getOffset(timestamp) / 60000
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isSameDay(timestamp1: Long, timestamp2: Long) = isSameDay(Date(timestamp1), Date(timestamp2))
|
|
||||||
|
|
||||||
fun isSameDayGroup(timestamp1: Long, timestamp2: Long): Boolean {
|
|
||||||
val now = now()
|
|
||||||
if (now in (timestamp1 + 1) until timestamp2 || now in (timestamp2 + 1) until timestamp1)
|
|
||||||
return false
|
|
||||||
return isSameDay(Date(timestamp1), Date(timestamp2))
|
|
||||||
}
|
|
||||||
|
|
||||||
//Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
|
//Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0}
|
||||||
fun computeDiff(date1: Long, date2: Long): Map<TimeUnit, Long> {
|
fun computeDiff(date1: Long, date2: Long): Map<TimeUnit, Long>
|
||||||
val units: MutableList<TimeUnit> = ArrayList(EnumSet.allOf(TimeUnit::class.java))
|
fun age(milliseconds: Long, useShortText: Boolean, rh: ResourceHelper): String
|
||||||
units.reverse()
|
fun niceTimeScalar(time: Long, rh: ResourceHelper): String
|
||||||
val result: MutableMap<TimeUnit, Long> = LinkedHashMap()
|
fun qs(x: Double, numDigits: Int): String
|
||||||
var millisecondsRest = date2 - date1
|
fun formatHHMM(timeAsSeconds: Int): String
|
||||||
for (unit in units) {
|
|
||||||
val diff = unit.convert(millisecondsRest, TimeUnit.MILLISECONDS)
|
|
||||||
val diffInMillisecondsForUnit = unit.toMillis(diff)
|
|
||||||
millisecondsRest -= diffInMillisecondsForUnit
|
|
||||||
result[unit] = diff
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun age(milliseconds: Long, useShortText: Boolean, rh: ResourceHelper): String {
|
|
||||||
val diff = computeDiff(0L, milliseconds)
|
|
||||||
var days = " " + rh.gs(R.string.days) + " "
|
|
||||||
var hours = " " + rh.gs(R.string.hours) + " "
|
|
||||||
var minutes = " " + rh.gs(R.string.unit_minutes) + " "
|
|
||||||
if (useShortText) {
|
|
||||||
days = rh.gs(R.string.shortday)
|
|
||||||
hours = rh.gs(R.string.shorthour)
|
|
||||||
minutes = rh.gs(R.string.shortminute)
|
|
||||||
}
|
|
||||||
var result = ""
|
|
||||||
if (diff.getOrDefault(TimeUnit.DAYS, -1) > 0) result += diff[TimeUnit.DAYS].toString() + days
|
|
||||||
if (diff.getOrDefault(TimeUnit.HOURS, -1) > 0) result += diff[TimeUnit.HOURS].toString() + hours
|
|
||||||
if (diff[TimeUnit.DAYS] == 0L) result += diff[TimeUnit.MINUTES].toString() + minutes
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
fun niceTimeScalar(time: Long, rh: ResourceHelper): String {
|
|
||||||
var t = time
|
|
||||||
var unit = rh.gs(R.string.unit_second)
|
|
||||||
t /= 1000
|
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_seconds)
|
|
||||||
if (t > 59) {
|
|
||||||
unit = rh.gs(R.string.unit_minute)
|
|
||||||
t /= 60
|
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_minutes)
|
|
||||||
if (t > 59) {
|
|
||||||
unit = rh.gs(R.string.unit_hour)
|
|
||||||
t /= 60
|
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_hours)
|
|
||||||
if (t > 24) {
|
|
||||||
unit = rh.gs(R.string.unit_day)
|
|
||||||
t /= 24
|
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_days)
|
|
||||||
if (t > 28) {
|
|
||||||
unit = rh.gs(R.string.unit_week)
|
|
||||||
t /= 7
|
|
||||||
@Suppress("KotlinConstantConditions")
|
|
||||||
if (t != 1L) unit = rh.gs(R.string.unit_weeks)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if (t != 1) unit = unit + "s"; //implemented plurality in every step, because in other languages plurality of time is not every time adding the same character
|
|
||||||
return qs(t.toDouble(), 0) + " " + unit
|
|
||||||
}
|
|
||||||
|
|
||||||
fun qs(x: Double, numDigits: Int): String {
|
|
||||||
var digits = numDigits
|
|
||||||
if (digits == -1) {
|
|
||||||
digits = 0
|
|
||||||
if ((x.toInt() % x == 0.0)) {
|
|
||||||
digits++
|
|
||||||
if ((x.toInt() * 10 / 10).toDouble() != x) {
|
|
||||||
digits++
|
|
||||||
if ((x.toInt() * 100 / 100).toDouble() != x) digits++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dfs == null) {
|
|
||||||
val localDfs = DecimalFormatSymbols()
|
|
||||||
localDfs.decimalSeparator = '.'
|
|
||||||
dfs = localDfs // avoid race condition
|
|
||||||
}
|
|
||||||
val thisDf: DecimalFormat?
|
|
||||||
// use singleton if on ui thread otherwise allocate new as DecimalFormat is not thread safe
|
|
||||||
if (Thread.currentThread().id == 1L) {
|
|
||||||
if (df == null) {
|
|
||||||
val localDf = DecimalFormat("#", dfs)
|
|
||||||
localDf.minimumIntegerDigits = 1
|
|
||||||
df = localDf // avoid race condition
|
|
||||||
}
|
|
||||||
thisDf = df
|
|
||||||
} else {
|
|
||||||
thisDf = DecimalFormat("#", dfs)
|
|
||||||
}
|
|
||||||
thisDf?.maximumFractionDigits = digits
|
|
||||||
return thisDf?.format(x) ?: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
fun formatHHMM(timeAsSeconds: Int): String {
|
|
||||||
val hour = timeAsSeconds / 60 / 60
|
|
||||||
val minutes = (timeAsSeconds - hour * 60 * 60) / 60
|
|
||||||
val df = DecimalFormat("00")
|
|
||||||
return df.format(hour.toLong()) + ":" + df.format(minutes.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.O)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
fun timeZoneByOffset(offsetInMilliseconds: Long): TimeZone =
|
fun timeZoneByOffset(offsetInMilliseconds: Long): TimeZone
|
||||||
TimeZone.getTimeZone(
|
fun timeStampToUtcDateMillis(timestamp: Long): Long
|
||||||
if (offsetInMilliseconds == 0L) ZoneId.of("UTC")
|
fun mergeUtcDateToTimestamp(timestamp: Long, dateUtcMillis: Long): Long
|
||||||
else ZoneId.getAvailableZoneIds()
|
fun mergeHourMinuteToTimestamp(timestamp: Long, hour: Int, minute: Int, randomSecond: Boolean = false): Long
|
||||||
.stream()
|
|
||||||
.map(ZoneId::of)
|
|
||||||
.filter { z -> z.rules.getOffset(Instant.now()).totalSeconds == ZoneOffset.ofHours((offsetInMilliseconds / 1000 / 3600).toInt()).totalSeconds }
|
|
||||||
.collect(Collectors.toList())
|
|
||||||
.firstOrNull() ?: ZoneId.of("UTC")
|
|
||||||
)
|
|
||||||
|
|
||||||
fun timeStampToUtcDateMillis(timestamp: Long): Long {
|
|
||||||
val current = Calendar.getInstance().apply { timeInMillis = timestamp }
|
|
||||||
return Calendar.getInstance().apply {
|
|
||||||
set(Calendar.YEAR, current[Calendar.YEAR])
|
|
||||||
set(Calendar.MONTH, current[Calendar.MONTH])
|
|
||||||
set(Calendar.DAY_OF_MONTH, current[Calendar.DAY_OF_MONTH])
|
|
||||||
}.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergeUtcDateToTimestamp(timestamp: Long, dateUtcMillis: Long): Long {
|
|
||||||
val selected = Calendar.getInstance().apply { timeInMillis = dateUtcMillis }
|
|
||||||
return Calendar.getInstance().apply {
|
|
||||||
timeInMillis = timestamp
|
|
||||||
set(Calendar.YEAR, selected[Calendar.YEAR])
|
|
||||||
set(Calendar.MONTH, selected[Calendar.MONTH])
|
|
||||||
set(Calendar.DAY_OF_MONTH, selected[Calendar.DAY_OF_MONTH])
|
|
||||||
}.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mergeHourMinuteToTimestamp(timestamp: Long, hour: Int, minute: Int, randomSecond: Boolean = false): Long {
|
|
||||||
return Calendar.getInstance().apply {
|
|
||||||
timeInMillis = timestamp
|
|
||||||
set(Calendar.HOUR_OF_DAY, hour)
|
|
||||||
set(Calendar.MINUTE, minute)
|
|
||||||
if (randomSecond) set(Calendar.SECOND, seconds++)
|
|
||||||
}.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private val timeStrings = LongSparseArray<String>()
|
|
||||||
private var seconds: Int = (SecureRandom().nextDouble() * 59.0).toInt()
|
|
||||||
|
|
||||||
// singletons to avoid repeated allocation
|
|
||||||
private var dfs: DecimalFormatSymbols? = null
|
|
||||||
private var df: DecimalFormat? = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
<vector android:height="400dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="400dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M10.744,0.074L10.885,1.416"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M13.113,22.599L13.254,23.942"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M9.504,0.27L9.784,1.591"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M14.214,22.425L14.495,23.745"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M8.29,0.595L8.708,1.88"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M15.291,22.136L15.708,23.42"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M7.118,1.046L7.667,2.279"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M16.332,21.737L16.881,22.97"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M4.945,2.3L5.739,3.392"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M18.26,20.623L19.053,21.716"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M3.969,3.091L4.873,4.094"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M19.126,19.922L20.029,20.925"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M3.081,3.979L4.084,4.882"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M19.914,19.133L20.917,20.037"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M2.291,4.955L3.383,5.749"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M20.616,18.267L21.708,19.061"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M1.036,7.128L2.27,7.677"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M21.729,16.339L22.962,16.888"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.586,8.3L1.871,8.718"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.128,15.298L23.412,15.715"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.261,9.514L1.582,9.794"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.416,14.221L23.737,14.502"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.065,10.754L1.408,10.895"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.591,13.12L23.934,13.261"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.065,13.263L1.408,13.122"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.591,10.894L23.933,10.753"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.262,14.503L1.582,14.223"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.416,9.793L23.737,9.512"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M0.587,15.717L1.871,15.299"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M22.128,8.716L23.412,8.299"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M1.037,16.889L2.271,16.34"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M21.728,7.676L22.962,7.126"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M2.291,19.062L3.384,18.268"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M20.615,5.747L21.707,4.954"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M3.082,20.038L4.085,19.134"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M19.913,4.881L20.917,3.978"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M3.97,20.926L4.874,19.923"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M19.125,4.093L20.028,3.09"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M4.946,21.716L5.74,20.624"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M18.258,3.392L19.052,2.299"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M7.119,22.971L7.668,21.737"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M16.33,2.278L16.879,1.045"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M8.292,23.421L8.709,22.137"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M15.29,1.879L15.707,0.595"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M9.505,23.746L9.786,22.425"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M14.213,1.591L14.494,0.27"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M10.746,23.942L10.887,22.599"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#00000000"
|
|
||||||
android:pathData="M13.112,1.416L13.253,0.073"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M11.999,0.008L11.999,2.708"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M11.999,21.307L11.999,24.008"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M23.999,12L21.298,12"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M2.699,12L-0.001,12"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M5.999,1.616L7.349,3.954"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M16.648,20.061L17.999,22.4"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M22.387,6.001L20.048,7.351"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M3.941,16.651L1.602,18.001"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M1.606,6.008L3.945,7.358"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M20.052,16.658L22.391,18.008"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M17.992,1.612L16.642,3.95"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M7.342,20.057L5.992,22.396"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
</vector>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<vector android:height="400dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="400dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FFFFFF" android:pathData="M11.999,4.906c-0.104,0 -0.188,0.084 -0.188,0.188V12c0,0.104 0.084,0.188 0.188,0.188c0.104,0 0.188,-0.084 0.188,-0.188V5.094C12.186,4.99 12.102,4.906 11.999,4.906zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z"/>
|
|
||||||
</vector>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<vector android:height="400dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="400dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FFFFFF" android:pathData="M11.999,1.406c-0.104,0 -0.188,0.084 -0.188,0.188V12c0,0.104 0.084,0.188 0.188,0.188c0.104,0 0.188,-0.084 0.188,-0.188V1.594C12.186,1.49 12.102,1.406 11.999,1.406zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z"/>
|
|
||||||
</vector>
|
|
|
@ -1,4 +0,0 @@
|
||||||
<vector android:height="400dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="400dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FF1313" android:pathData="M12.198,11.462v-0.237c0,-0.077 -0.05,-0.131 -0.114,-0.164V0.508c0,-0.047 -0.038,-0.086 -0.086,-0.086c-0.047,0 -0.086,0.038 -0.086,0.086v10.553c-0.063,0.033 -0.114,0.087 -0.114,0.164v0.238c-0.219,0.082 -0.376,0.29 -0.376,0.537s0.157,0.455 0.376,0.537v0.92c0,0.11 0.089,0.2 0.2,0.2s0.2,-0.089 0.2,-0.2v-0.919c0.221,-0.081 0.381,-0.289 0.381,-0.538S12.419,11.543 12.198,11.462zM11.999,12.094c-0.047,0 -0.086,-0.038 -0.086,-0.086s0.039,-0.086 0.086,-0.086c0.047,0 0.086,0.038 0.086,0.086S12.046,12.094 11.999,12.094z"/>
|
|
||||||
</vector>
|
|
|
@ -1,39 +0,0 @@
|
||||||
<vector android:height="400dp" android:viewportHeight="24"
|
|
||||||
android:viewportWidth="24" android:width="400dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M11.999,0.008L11.999,2.708"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M11.999,21.307L11.999,24.008"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M23.999,12L21.298,12"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M2.699,12L-0.001,12"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M5.999,1.616L7.349,3.954"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M16.648,20.061L17.999,22.4"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M22.387,6.001L20.048,7.351"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M3.941,16.651L1.602,18.001"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M1.606,6.008L3.945,7.358"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M20.052,16.658L22.391,18.008"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M17.992,1.612L16.642,3.95"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
<path android:fillColor="#FFFFFF"
|
|
||||||
android:pathData="M7.342,20.057L5.992,22.396"
|
|
||||||
android:strokeColor="#FFFFFF" android:strokeWidth="0.1417"/>
|
|
||||||
</vector>
|
|
|
@ -8,7 +8,6 @@ import info.nightscout.androidaps.MainApp
|
||||||
import info.nightscout.androidaps.danar.di.DanaRModule
|
import info.nightscout.androidaps.danar.di.DanaRModule
|
||||||
import info.nightscout.androidaps.insight.di.InsightDatabaseModule
|
import info.nightscout.androidaps.insight.di.InsightDatabaseModule
|
||||||
import info.nightscout.androidaps.insight.di.InsightModule
|
import info.nightscout.androidaps.insight.di.InsightModule
|
||||||
import info.nightscout.plugins.sync.di.OpenHumansModule
|
|
||||||
import info.nightscout.androidaps.plugins.pump.common.di.RileyLinkModule
|
import info.nightscout.androidaps.plugins.pump.common.di.RileyLinkModule
|
||||||
import info.nightscout.androidaps.plugins.pump.eopatch.dagger.EopatchModule
|
import info.nightscout.androidaps.plugins.pump.eopatch.dagger.EopatchModule
|
||||||
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
import info.nightscout.androidaps.plugins.pump.medtronic.di.MedtronicModule
|
||||||
|
@ -24,6 +23,7 @@ import info.nightscout.insulin.di.InsulinModule
|
||||||
import info.nightscout.plugins.aps.di.ApsModule
|
import info.nightscout.plugins.aps.di.ApsModule
|
||||||
import info.nightscout.plugins.constraints.di.PluginsConstraintsModule
|
import info.nightscout.plugins.constraints.di.PluginsConstraintsModule
|
||||||
import info.nightscout.plugins.di.PluginsModule
|
import info.nightscout.plugins.di.PluginsModule
|
||||||
|
import info.nightscout.plugins.sync.di.OpenHumansModule
|
||||||
import info.nightscout.plugins.sync.di.SyncModule
|
import info.nightscout.plugins.sync.di.SyncModule
|
||||||
import info.nightscout.pump.combo.di.ComboModule
|
import info.nightscout.pump.combo.di.ComboModule
|
||||||
import info.nightscout.pump.combov2.di.ComboV2Module
|
import info.nightscout.pump.combov2.di.ComboV2Module
|
||||||
|
@ -31,11 +31,9 @@ import info.nightscout.pump.common.di.PumpCommonModule
|
||||||
import info.nightscout.pump.dana.di.DanaHistoryModule
|
import info.nightscout.pump.dana.di.DanaHistoryModule
|
||||||
import info.nightscout.pump.dana.di.DanaModule
|
import info.nightscout.pump.dana.di.DanaModule
|
||||||
import info.nightscout.pump.danars.di.DanaRSModule
|
import info.nightscout.pump.danars.di.DanaRSModule
|
||||||
import info.nightscout.pump.medtrum.di.MedtrumModule
|
|
||||||
import info.nightscout.pump.diaconn.di.DiaconnG8Module
|
import info.nightscout.pump.diaconn.di.DiaconnG8Module
|
||||||
|
import info.nightscout.pump.medtrum.di.MedtrumModule
|
||||||
import info.nightscout.pump.virtual.di.VirtualPumpModule
|
import info.nightscout.pump.virtual.di.VirtualPumpModule
|
||||||
import info.nightscout.rx.di.RxModule
|
|
||||||
import info.nightscout.shared.di.SharedModule
|
|
||||||
import info.nightscout.shared.impl.di.SharedImplModule
|
import info.nightscout.shared.impl.di.SharedImplModule
|
||||||
import info.nightscout.source.di.SourceModule
|
import info.nightscout.source.di.SourceModule
|
||||||
import info.nightscout.ui.di.UiModule
|
import info.nightscout.ui.di.UiModule
|
||||||
|
@ -62,8 +60,6 @@ import javax.inject.Singleton
|
||||||
InsulinModule::class,
|
InsulinModule::class,
|
||||||
OpenHumansModule::class,
|
OpenHumansModule::class,
|
||||||
PluginsModule::class,
|
PluginsModule::class,
|
||||||
RxModule::class,
|
|
||||||
SharedModule::class,
|
|
||||||
SharedImplModule::class,
|
SharedImplModule::class,
|
||||||
UiModule::class,
|
UiModule::class,
|
||||||
ValidatorsModule::class,
|
ValidatorsModule::class,
|
||||||
|
|
3
core/ui/src/main/res/values-sw600dp/layout.xml
Normal file
3
core/ui/src/main/res/values-sw600dp/layout.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<bool name="isTablet">true</bool>
|
||||||
|
</resources>
|
3
core/ui/src/main/res/values/layout.xml
Normal file
3
core/ui/src/main/res/values/layout.xml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<bool name="isTablet">false</bool>
|
||||||
|
</resources>
|
|
@ -17,5 +17,6 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
api "com.google.android.material:material:$material_version"
|
api "com.google.android.material:material:$material_version"
|
||||||
}
|
}
|
|
@ -32,7 +32,6 @@ import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventPreferenceChange
|
import info.nightscout.rx.events.EventPreferenceChange
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.shared.extensions.runOnUiThread
|
|
||||||
import info.nightscout.shared.extensions.toVisibility
|
import info.nightscout.shared.extensions.toVisibility
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import io.reactivex.rxjava3.core.Completable
|
import io.reactivex.rxjava3.core.Completable
|
||||||
|
@ -106,7 +105,7 @@ class MaintenanceFragment : DaggerFragment() {
|
||||||
onError = { aapsLogger.error("Error clearing databases", it) },
|
onError = { aapsLogger.error("Error clearing databases", it) },
|
||||||
onComplete = {
|
onComplete = {
|
||||||
rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.utils.R.string.key_units)))
|
rxBus.send(EventPreferenceChange(rh.gs(info.nightscout.core.utils.R.string.key_units)))
|
||||||
runOnUiThread { activity.recreate() }
|
info.nightscout.shared.extensions.runOnUiThread { activity.recreate() }
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
uel.log(Action.RESET_DATABASES, Sources.Maintenance)
|
uel.log(Action.RESET_DATABASES, Sources.Maintenance)
|
||||||
|
|
|
@ -16,6 +16,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
implementation project(':database:entities')
|
implementation project(':database:entities')
|
||||||
implementation project(':database:impl')
|
implementation project(':database:impl')
|
||||||
implementation project(':core:graphview')
|
implementation project(':core:graphview')
|
||||||
|
|
|
@ -34,6 +34,7 @@ import info.nightscout.rx.events.EventNewHistoryData
|
||||||
import info.nightscout.rx.events.EventPumpStatusChanged
|
import info.nightscout.rx.events.EventPumpStatusChanged
|
||||||
import info.nightscout.rx.events.EventUpdateOverviewCalcProgress
|
import info.nightscout.rx.events.EventUpdateOverviewCalcProgress
|
||||||
import info.nightscout.rx.logging.AAPSLogger
|
import info.nightscout.rx.logging.AAPSLogger
|
||||||
|
import info.nightscout.shared.impl.rx.bus.RxBusImpl
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -72,7 +73,7 @@ class OverviewPlugin @Inject constructor(
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
override val overviewBus = RxBus(aapsSchedulers, aapsLogger)
|
override val overviewBus = RxBusImpl(aapsSchedulers, aapsLogger)
|
||||||
|
|
||||||
override fun addNotificationWithDialogResponse(id: Int, text: String, level: Int, @StringRes actionButtonId: Int, title: String, message: String) {
|
override fun addNotificationWithDialogResponse(id: Int, text: String, level: Int, @StringRes actionButtonId: Int, title: String, message: String) {
|
||||||
rxBus.send(
|
rxBus.send(
|
||||||
|
|
|
@ -17,6 +17,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
implementation project(':database:entities')
|
implementation project(':database:entities')
|
||||||
implementation project(':database:impl')
|
implementation project(':database:impl')
|
||||||
implementation project(':core:interfaces')
|
implementation project(':core:interfaces')
|
||||||
|
|
|
@ -16,6 +16,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
implementation project(':database:entities')
|
implementation project(':database:entities')
|
||||||
implementation project(':database:impl')
|
implementation project(':database:impl')
|
||||||
implementation project(':core:main')
|
implementation project(':core:main')
|
||||||
|
|
|
@ -19,7 +19,6 @@ import info.nightscout.pump.combo.ruffyscripter.PumpState
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.bus.RxBus
|
import info.nightscout.rx.bus.RxBus
|
||||||
import info.nightscout.rx.events.EventQueueChanged
|
import info.nightscout.rx.events.EventQueueChanged
|
||||||
import info.nightscout.shared.extensions.runOnUiThread
|
|
||||||
import info.nightscout.shared.interfaces.ResourceHelper
|
import info.nightscout.shared.interfaces.ResourceHelper
|
||||||
import info.nightscout.shared.utils.DateUtil
|
import info.nightscout.shared.utils.DateUtil
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
|
@ -62,7 +61,7 @@ class ComboFragment : DaggerFragment() {
|
||||||
binding.comboRefreshButton.isEnabled = false
|
binding.comboRefreshButton.isEnabled = false
|
||||||
commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.user_request), object : Callback() {
|
commandQueue.readStatus(rh.gs(info.nightscout.core.ui.R.string.user_request), object : Callback() {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
runOnUiThread { binding.comboRefreshButton.isEnabled = true }
|
activity?.runOnUiThread { binding.comboRefreshButton.isEnabled = true }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -153,14 +152,17 @@ class ComboFragment : DaggerFragment() {
|
||||||
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
||||||
binding.comboInsulinstate.setTypeface(null, Typeface.NORMAL)
|
binding.comboInsulinstate.setTypeface(null, Typeface.NORMAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
PumpState.LOW -> {
|
PumpState.LOW -> {
|
||||||
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.omniYellowColor))
|
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.omniYellowColor))
|
||||||
binding.comboInsulinstate.setTypeface(null, Typeface.BOLD)
|
binding.comboInsulinstate.setTypeface(null, Typeface.BOLD)
|
||||||
}
|
}
|
||||||
|
|
||||||
PumpState.EMPTY -> {
|
PumpState.EMPTY -> {
|
||||||
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.warningColor))
|
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.warningColor))
|
||||||
binding.comboInsulinstate.setTypeface(null, Typeface.BOLD)
|
binding.comboInsulinstate.setTypeface(null, Typeface.BOLD)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
binding.comboInsulinstate.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
||||||
binding.comboInsulinstate.setTypeface(null, Typeface.NORMAL)
|
binding.comboInsulinstate.setTypeface(null, Typeface.NORMAL)
|
||||||
|
@ -175,10 +177,12 @@ class ComboFragment : DaggerFragment() {
|
||||||
binding.comboLastconnection.setText(R.string.combo_pump_connected_now)
|
binding.comboLastconnection.setText(R.string.combo_pump_connected_now)
|
||||||
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
comboPlugin.pump.lastSuccessfulCmdTime + 30 * 60 * 1000 < System.currentTimeMillis() -> {
|
comboPlugin.pump.lastSuccessfulCmdTime + 30 * 60 * 1000 < System.currentTimeMillis() -> {
|
||||||
binding.comboLastconnection.text = rh.gs(R.string.combo_no_pump_connection, min)
|
binding.comboLastconnection.text = rh.gs(R.string.combo_no_pump_connection, min)
|
||||||
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.warningColor))
|
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.warningColor))
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
binding.comboLastconnection.text = minAgo
|
binding.comboLastconnection.text = minAgo
|
||||||
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
binding.comboLastconnection.setTextColor(rh.gac(context, info.nightscout.core.ui.R.attr.defaultTextColor))
|
||||||
|
|
|
@ -26,6 +26,7 @@ android {
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(':app-wear-shared:shared')
|
implementation project(':app-wear-shared:shared')
|
||||||
|
implementation project(':app-wear-shared:shared-impl')
|
||||||
implementation project(':core:libraries')
|
implementation project(':core:libraries')
|
||||||
implementation project(':core:interfaces')
|
implementation project(':core:interfaces')
|
||||||
implementation project(':core:utils')
|
implementation project(':core:utils')
|
||||||
|
|
|
@ -27,6 +27,7 @@ import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
interface IAlarmRegistry {
|
interface IAlarmRegistry {
|
||||||
|
|
||||||
fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean = false): Maybe<AlarmCode>
|
fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean = false): Maybe<AlarmCode>
|
||||||
fun add(patchAeCodes: Set<PatchAeCode>)
|
fun add(patchAeCodes: Set<PatchAeCode>)
|
||||||
fun remove(alarmCode: AlarmCode): Maybe<AlarmCode>
|
fun remove(alarmCode: AlarmCode): Maybe<AlarmCode>
|
||||||
|
@ -34,11 +35,13 @@ interface IAlarmRegistry {
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||||
|
|
||||||
@Inject lateinit var mContext: Context
|
@Inject lateinit var mContext: Context
|
||||||
@Inject lateinit var pm: IPreferenceManager
|
@Inject lateinit var pm: IPreferenceManager
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||||
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
|
||||||
private lateinit var mOsAlarmManager: AlarmManager
|
private lateinit var mOsAlarmManager: AlarmManager
|
||||||
private var mDisposable: Disposable? = null
|
private var mDisposable: Disposable? = null
|
||||||
|
@ -49,19 +52,21 @@ class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||||
mDisposable = pm.observePatchLifeCycle()
|
mDisposable = pm.observePatchLifeCycle()
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
when(it){
|
when (it) {
|
||||||
PatchLifecycle.REMOVE_NEEDLE_CAP -> {
|
PatchLifecycle.REMOVE_NEEDLE_CAP -> {
|
||||||
val triggerAfter = pm.getPatchConfig().patchWakeupTimestamp + TimeUnit.HOURS.toMillis(1) - System.currentTimeMillis()
|
val triggerAfter = pm.getPatchConfig().patchWakeupTimestamp + TimeUnit.HOURS.toMillis(1) - System.currentTimeMillis()
|
||||||
compositeDisposable.add(add(AlarmCode.A020, triggerAfter).subscribe())
|
compositeDisposable.add(add(AlarmCode.A020, triggerAfter).subscribe())
|
||||||
}
|
}
|
||||||
PatchLifecycle.ACTIVATED -> {
|
|
||||||
|
PatchLifecycle.ACTIVATED -> {
|
||||||
|
|
||||||
}
|
}
|
||||||
PatchLifecycle.SHUTDOWN -> {
|
|
||||||
|
PatchLifecycle.SHUTDOWN -> {
|
||||||
val sources = ArrayList<Maybe<*>>()
|
val sources = ArrayList<Maybe<*>>()
|
||||||
sources.add(Maybe.just(true))
|
sources.add(Maybe.just(true))
|
||||||
pm.getAlarms().occurred.let{ occurredAlarms ->
|
pm.getAlarms().occurred.let { occurredAlarms ->
|
||||||
if(occurredAlarms.isNotEmpty()){
|
if (occurredAlarms.isNotEmpty()) {
|
||||||
occurredAlarms.keys.forEach { alarmCode ->
|
occurredAlarms.keys.forEach { alarmCode ->
|
||||||
sources.add(
|
sources.add(
|
||||||
Maybe.just(alarmCode)
|
Maybe.just(alarmCode)
|
||||||
|
@ -71,30 +76,30 @@ class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pm.getAlarms().registered.let{ registeredAlarms ->
|
pm.getAlarms().registered.let { registeredAlarms ->
|
||||||
if(registeredAlarms.isNotEmpty()){
|
if (registeredAlarms.isNotEmpty()) {
|
||||||
registeredAlarms.keys.forEach { alarmCode ->
|
registeredAlarms.keys.forEach { alarmCode ->
|
||||||
sources.add(remove(alarmCode))
|
sources.add(remove(alarmCode))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compositeDisposable.add(Maybe.concat(sources)
|
compositeDisposable.add(Maybe.concat(sources)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
pm.getAlarms().clear()
|
pm.getAlarms().clear()
|
||||||
pm.flushAlarms()
|
pm.flushAlarms()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> Unit
|
else -> Unit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean): Maybe<AlarmCode> {
|
override fun add(alarmCode: AlarmCode, triggerAfter: Long, isFirst: Boolean): Maybe<AlarmCode> {
|
||||||
if(pm.getAlarms().occurred.containsKey(alarmCode)){
|
if (pm.getAlarms().occurred.containsKey(alarmCode)) {
|
||||||
return Maybe.just(alarmCode)
|
return Maybe.just(alarmCode)
|
||||||
}else {
|
} else {
|
||||||
val triggerTimeMilli = System.currentTimeMillis() + triggerAfter
|
val triggerTimeMilli = System.currentTimeMillis() + triggerAfter
|
||||||
pm.getAlarms().register(alarmCode, triggerAfter)
|
pm.getAlarms().register(alarmCode, triggerAfter)
|
||||||
pm.flushAlarms()
|
pm.flushAlarms()
|
||||||
|
@ -109,11 +114,11 @@ class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||||
override fun add(patchAeCodes: Set<PatchAeCode>) {
|
override fun add(patchAeCodes: Set<PatchAeCode>) {
|
||||||
compositeDisposable.add(
|
compositeDisposable.add(
|
||||||
Observable.fromIterable(patchAeCodes)
|
Observable.fromIterable(patchAeCodes)
|
||||||
.filter{patchAeCodeItem -> AlarmCode.findByPatchAeCode(patchAeCodeItem.aeValue) != null}
|
.filter { patchAeCodeItem -> AlarmCode.findByPatchAeCode(patchAeCodeItem.aeValue) != null }
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.filter { aeCodes -> AlarmCode.findByPatchAeCode(aeCodes.aeValue) != null }
|
.filter { aeCodes -> AlarmCode.findByPatchAeCode(aeCodes.aeValue) != null }
|
||||||
.flatMapMaybe{aeCodeResponse -> add(AlarmCode.findByPatchAeCode(aeCodeResponse.aeValue)!!, 0L, true)}
|
.flatMapMaybe { aeCodeResponse -> add(AlarmCode.findByPatchAeCode(aeCodeResponse.aeValue)!!, 0L, true) }
|
||||||
.subscribe()
|
.subscribe()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,21 +126,21 @@ class AlarmRegistry @Inject constructor() : IAlarmRegistry {
|
||||||
return Maybe.fromCallable {
|
return Maybe.fromCallable {
|
||||||
cancelOsAlarmInternal(alarmCode)
|
cancelOsAlarmInternal(alarmCode)
|
||||||
val pendingIntent = createPendingIntent(alarmCode, 0)
|
val pendingIntent = createPendingIntent(alarmCode, 0)
|
||||||
aapsLogger.debug("[${alarmCode}] OS Alarm added. ${DateUtil(mContext).toISOString(triggerTime)}")
|
aapsLogger.debug("[${alarmCode}] OS Alarm added. ${dateUtil.toISOString(triggerTime)}")
|
||||||
mOsAlarmManager.setAlarmClock(AlarmClockInfo(triggerTime, pendingIntent), pendingIntent)
|
mOsAlarmManager.setAlarmClock(AlarmClockInfo(triggerTime, pendingIntent), pendingIntent)
|
||||||
alarmCode
|
alarmCode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove(alarmCode: AlarmCode): Maybe<AlarmCode> {
|
override fun remove(alarmCode: AlarmCode): Maybe<AlarmCode> {
|
||||||
return if(pm.getAlarms().registered.containsKey(alarmCode)) {
|
return if (pm.getAlarms().registered.containsKey(alarmCode)) {
|
||||||
cancelOsAlarms(alarmCode)
|
cancelOsAlarms(alarmCode)
|
||||||
.doOnSuccess {
|
.doOnSuccess {
|
||||||
pm.getAlarms().unregister(alarmCode)
|
pm.getAlarms().unregister(alarmCode)
|
||||||
pm.flushAlarms()
|
pm.flushAlarms()
|
||||||
}
|
}
|
||||||
.map { alarmCode }
|
.map { alarmCode }
|
||||||
}else{
|
} else {
|
||||||
Maybe.just(alarmCode)
|
Maybe.just(alarmCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.common.definition.Omnipod
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.DashHistoryDatabase
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.HistoryRecordDao
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.database.HistoryRecordDao
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.mapper.HistoryMapper
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.history.mapper.HistoryMapper
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.endecry
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.message.MessagePacket
|
||||||
import info.nightscout.core.utils.toHex
|
import info.nightscout.core.utils.toHex
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.spongycastle.util.encoders.Hex
|
import org.spongycastle.util.encoders.Hex
|
||||||
|
|
|
@ -4,7 +4,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.Rand
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator
|
import info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.pod.util.X25519KeyGenerator
|
||||||
import info.nightscout.core.utils.toHex
|
import info.nightscout.core.utils.toHex
|
||||||
import info.nightscout.interfaces.Config
|
import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import info.nightscout.sharedtests.TestBase
|
import info.nightscout.sharedtests.TestBase
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
||||||
|
|
||||||
import info.nightscout.core.utils.toHex
|
import info.nightscout.core.utils.toHex
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.spongycastle.util.encoders.Hex
|
import org.spongycastle.util.encoders.Hex
|
||||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.omnipod.dash.driver.comm.session
|
||||||
|
|
||||||
import info.nightscout.core.utils.toHex
|
import info.nightscout.core.utils.toHex
|
||||||
import info.nightscout.interfaces.Config
|
import info.nightscout.interfaces.Config
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import info.nightscout.sharedtests.TestBase
|
import info.nightscout.sharedtests.TestBase
|
||||||
import org.junit.jupiter.api.Assertions
|
import org.junit.jupiter.api.Assertions
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
|
@ -37,6 +37,8 @@ dependencies {
|
||||||
implementation project(':pump:rileylink')
|
implementation project(':pump:rileylink')
|
||||||
implementation project(':pump:omnipod-common')
|
implementation project(':pump:omnipod-common')
|
||||||
|
|
||||||
|
testImplementation project(':app-wear-shared:shared-impl')
|
||||||
|
|
||||||
api "androidx.room:room-ktx:$room_version"
|
api "androidx.room:room-ktx:$room_version"
|
||||||
api "androidx.room:room-runtime:$room_version"
|
api "androidx.room:room-runtime:$room_version"
|
||||||
api "androidx.room:room-rxjava3:$room_version"
|
api "androidx.room:room-rxjava3:$room_version"
|
||||||
|
|
|
@ -2,10 +2,10 @@ package info.nightscout.androidaps.plugins.pump.omnipod.eros.manager
|
||||||
|
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.FirmwareVersion
|
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.FirmwareVersion
|
||||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.PodProgressStatus
|
import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.PodProgressStatus
|
||||||
import info.nightscout.rx.TestAapsSchedulers
|
import info.nightscout.shared.impl.rx.bus.RxBusImpl
|
||||||
import info.nightscout.rx.bus.RxBus
|
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.sharedtests.TestBase
|
import info.nightscout.sharedtests.TestBase
|
||||||
|
import info.nightscout.sharedtests.rx.TestAapsSchedulers
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import org.joda.time.DateTimeUtils
|
import org.joda.time.DateTimeUtils
|
||||||
import org.joda.time.DateTimeZone
|
import org.joda.time.DateTimeZone
|
||||||
|
@ -19,7 +19,7 @@ class AapsErosPodStateManagerTest : TestBase() {
|
||||||
|
|
||||||
@Mock lateinit var sp: SP
|
@Mock lateinit var sp: SP
|
||||||
|
|
||||||
private val rxBus = RxBus(TestAapsSchedulers(), aapsLogger)
|
private val rxBus = RxBusImpl(TestAapsSchedulers(), aapsLogger)
|
||||||
|
|
||||||
@Test fun times() {
|
@Test fun times() {
|
||||||
val timeZone = DateTimeZone.UTC
|
val timeZone = DateTimeZone.UTC
|
||||||
|
|
|
@ -6,8 +6,6 @@ import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.WearApp
|
import info.nightscout.androidaps.WearApp
|
||||||
import info.nightscout.rx.di.RxModule
|
|
||||||
import info.nightscout.shared.di.SharedModule
|
|
||||||
import info.nightscout.shared.impl.di.SharedImplModule
|
import info.nightscout.shared.impl.di.SharedImplModule
|
||||||
import kotlinx.datetime.Clock
|
import kotlinx.datetime.Clock
|
||||||
|
|
||||||
|
@ -16,8 +14,6 @@ import kotlinx.datetime.Clock
|
||||||
includes = [
|
includes = [
|
||||||
WearModule.AppBindings::class,
|
WearModule.AppBindings::class,
|
||||||
WearActivitiesModule::class,
|
WearActivitiesModule::class,
|
||||||
RxModule::class,
|
|
||||||
SharedModule::class,
|
|
||||||
SharedImplModule::class
|
SharedImplModule::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -35,15 +35,15 @@ import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
import info.nightscout.rx.weardata.CUSTOM_VERSION
|
||||||
import info.nightscout.rx.weardata.CwfData
|
import info.nightscout.rx.weardata.CwfData
|
||||||
import info.nightscout.rx.weardata.ResFileMap
|
|
||||||
import info.nightscout.rx.weardata.CwfResDataMap
|
|
||||||
import info.nightscout.rx.weardata.CwfMetadataKey
|
import info.nightscout.rx.weardata.CwfMetadataKey
|
||||||
import info.nightscout.rx.weardata.CwfMetadataMap
|
import info.nightscout.rx.weardata.CwfMetadataMap
|
||||||
import info.nightscout.rx.weardata.ResData
|
import info.nightscout.rx.weardata.CwfResDataMap
|
||||||
import info.nightscout.rx.weardata.ResFormat
|
|
||||||
import info.nightscout.rx.weardata.EventData
|
import info.nightscout.rx.weardata.EventData
|
||||||
import info.nightscout.rx.weardata.JsonKeyValues
|
import info.nightscout.rx.weardata.JsonKeyValues
|
||||||
import info.nightscout.rx.weardata.JsonKeys.*
|
import info.nightscout.rx.weardata.JsonKeys.*
|
||||||
|
import info.nightscout.rx.weardata.ResData
|
||||||
|
import info.nightscout.rx.weardata.ResFileMap
|
||||||
|
import info.nightscout.rx.weardata.ResFormat
|
||||||
import info.nightscout.rx.weardata.ViewKeys
|
import info.nightscout.rx.weardata.ViewKeys
|
||||||
import info.nightscout.rx.weardata.ZipWatchfaceFormat
|
import info.nightscout.rx.weardata.ZipWatchfaceFormat
|
||||||
import info.nightscout.shared.extensions.toVisibility
|
import info.nightscout.shared.extensions.toVisibility
|
||||||
|
@ -208,7 +208,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
it.clearColorFilter()
|
it.clearColorFilter()
|
||||||
view.setImageDrawable(it)
|
view.setImageDrawable(it)
|
||||||
} ?: apply {
|
} ?: apply {
|
||||||
view.setImageDrawable(id.defaultDrawable?.let {resources.getDrawable(it)})
|
view.setImageDrawable(id.defaultDrawable?.let { resources.getDrawable(it) })
|
||||||
if (viewJson.has(COLOR.key))
|
if (viewJson.has(COLOR.key))
|
||||||
view.setColorFilter(getColor(viewJson.optString(COLOR.key)))
|
view.setColorFilter(getColor(viewJson.optString(COLOR.key)))
|
||||||
else
|
else
|
||||||
|
@ -217,7 +217,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} ?:apply {
|
} ?: apply {
|
||||||
view.visibility = View.GONE
|
view.visibility = View.GONE
|
||||||
if (view is TextView) {
|
if (view is TextView) {
|
||||||
view.text = ""
|
view.text = ""
|
||||||
|
@ -301,7 +301,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
}
|
}
|
||||||
val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
|
val metadataMap = ZipWatchfaceFormat.loadMetadata(json)
|
||||||
val drawableDataMap: CwfResDataMap = mutableMapOf()
|
val drawableDataMap: CwfResDataMap = mutableMapOf()
|
||||||
getResourceByteArray(info.nightscout.shared.R.drawable.watchface_custom)?.let {
|
getResourceByteArray(info.nightscout.shared.impl.R.drawable.watchface_custom)?.let {
|
||||||
drawableDataMap[ResFileMap.CUSTOM_WATCHFACE.fileName] = ResData(it, ResFormat.PNG)
|
drawableDataMap[ResFileMap.CUSTOM_WATCHFACE.fileName] = ResData(it, ResFormat.PNG)
|
||||||
}
|
}
|
||||||
return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap))
|
return EventData.ActionSetCustomWatchface(CwfData(json.toString(4), metadataMap, drawableDataMap))
|
||||||
|
@ -394,7 +394,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
@StringRes val pref: Int?,
|
@StringRes val pref: Int?,
|
||||||
@IdRes val defaultDrawable: Int?,
|
@IdRes val defaultDrawable: Int?,
|
||||||
val customDrawable: ResFileMap?,
|
val customDrawable: ResFileMap?,
|
||||||
val customHigh:ResFileMap?,
|
val customHigh: ResFileMap?,
|
||||||
val customLow: ResFileMap?
|
val customLow: ResFileMap?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
ViewKeys.BACKGROUND.key,
|
ViewKeys.BACKGROUND.key,
|
||||||
R.id.background,
|
R.id.background,
|
||||||
null,
|
null,
|
||||||
info.nightscout.shared.R.drawable.background,
|
info.nightscout.shared.impl.R.drawable.background,
|
||||||
ResFileMap.BACKGROUND,
|
ResFileMap.BACKGROUND,
|
||||||
ResFileMap.BACKGROUND_HIGH,
|
ResFileMap.BACKGROUND_HIGH,
|
||||||
ResFileMap.BACKGROUND_LOW
|
ResFileMap.BACKGROUND_LOW
|
||||||
|
@ -448,7 +448,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
ViewKeys.COVER_PLATE.key,
|
ViewKeys.COVER_PLATE.key,
|
||||||
R.id.cover_plate,
|
R.id.cover_plate,
|
||||||
null,
|
null,
|
||||||
info.nightscout.shared.R.drawable.simplified_dial,
|
info.nightscout.shared.impl.R.drawable.simplified_dial,
|
||||||
ResFileMap.COVER_PLATE,
|
ResFileMap.COVER_PLATE,
|
||||||
ResFileMap.COVER_PLATE_HIGH,
|
ResFileMap.COVER_PLATE_HIGH,
|
||||||
ResFileMap.COVER_PLATE_LOW
|
ResFileMap.COVER_PLATE_LOW
|
||||||
|
@ -457,7 +457,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
ViewKeys.HOUR_HAND.key,
|
ViewKeys.HOUR_HAND.key,
|
||||||
R.id.hour_hand,
|
R.id.hour_hand,
|
||||||
null,
|
null,
|
||||||
info.nightscout.shared.R.drawable.hour_hand,
|
info.nightscout.shared.impl.R.drawable.hour_hand,
|
||||||
ResFileMap.HOUR_HAND,
|
ResFileMap.HOUR_HAND,
|
||||||
ResFileMap.HOUR_HAND_HIGH,
|
ResFileMap.HOUR_HAND_HIGH,
|
||||||
ResFileMap.HOUR_HAND_LOW
|
ResFileMap.HOUR_HAND_LOW
|
||||||
|
@ -466,7 +466,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
ViewKeys.MINUTE_HAND.key,
|
ViewKeys.MINUTE_HAND.key,
|
||||||
R.id.minute_hand,
|
R.id.minute_hand,
|
||||||
null,
|
null,
|
||||||
info.nightscout.shared.R.drawable.minute_hand,
|
info.nightscout.shared.impl.R.drawable.minute_hand,
|
||||||
ResFileMap.MINUTE_HAND,
|
ResFileMap.MINUTE_HAND,
|
||||||
ResFileMap.MINUTE_HAND_HIGH,
|
ResFileMap.MINUTE_HAND_HIGH,
|
||||||
ResFileMap.MINUTE_HAND_LOW
|
ResFileMap.MINUTE_HAND_LOW
|
||||||
|
@ -475,7 +475,7 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
ViewKeys.SECOND_HAND.key,
|
ViewKeys.SECOND_HAND.key,
|
||||||
R.id.second_hand,
|
R.id.second_hand,
|
||||||
R.string.key_show_seconds,
|
R.string.key_show_seconds,
|
||||||
info.nightscout.shared.R.drawable.second_hand,
|
info.nightscout.shared.impl.R.drawable.second_hand,
|
||||||
ResFileMap.SECOND_HAND,
|
ResFileMap.SECOND_HAND,
|
||||||
ResFileMap.SECOND_HAND_HIGH,
|
ResFileMap.SECOND_HAND_HIGH,
|
||||||
ResFileMap.SECOND_HAND_LOW
|
ResFileMap.SECOND_HAND_LOW
|
||||||
|
@ -491,16 +491,25 @@ class CustomWatchface : BaseWatchFace() {
|
||||||
|
|
||||||
fun drawable(resources: Resources, drawableDataMap: CwfResDataMap, sgvLevel: Long): Drawable? = customDrawable?.let { cd ->
|
fun drawable(resources: Resources, drawableDataMap: CwfResDataMap, sgvLevel: Long): Drawable? = customDrawable?.let { cd ->
|
||||||
when (sgvLevel) {
|
when (sgvLevel) {
|
||||||
1L -> { customHigh?.let {drawableDataMap[customHigh.fileName]}?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources) }
|
1L -> {
|
||||||
0L -> { drawableDataMap[cd.fileName]?.toDrawable(resources) }
|
customHigh?.let { drawableDataMap[customHigh.fileName] }?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources)
|
||||||
-1L -> { customLow?.let {drawableDataMap[customLow.fileName]}?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources) }
|
}
|
||||||
|
|
||||||
|
0L -> {
|
||||||
|
drawableDataMap[cd.fileName]?.toDrawable(resources)
|
||||||
|
}
|
||||||
|
|
||||||
|
-1L -> {
|
||||||
|
customLow?.let { drawableDataMap[customLow.fileName] }?.toDrawable(resources) ?: drawableDataMap[cd.fileName]?.toDrawable(resources)
|
||||||
|
}
|
||||||
|
|
||||||
else -> drawableDataMap[cd.fileName]?.toDrawable(resources)
|
else -> drawableDataMap[cd.fileName]?.toDrawable(resources)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int,val customDrawable: ResFileMap?) {
|
private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int, val customDrawable: ResFileMap?) {
|
||||||
NONE("??", R.drawable.ic_invalid, ResFileMap.ARROW_NONE),
|
NONE("??", R.drawable.ic_invalid, ResFileMap.ARROW_NONE),
|
||||||
TRIPLE_UP("X", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
TRIPLE_UP("X", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
||||||
DOUBLE_UP("\u21c8", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
DOUBLE_UP("\u21c8", R.drawable.ic_doubleup, ResFileMap.ARROW_DOUBLE_UP),
|
||||||
|
@ -515,8 +524,8 @@ private enum class TrendArrowMap(val symbol: String, @DrawableRes val icon: Int,
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun drawable(direction: String?, resources: Resources, drawableDataMap: CwfResDataMap): Drawable {
|
fun drawable(direction: String?, resources: Resources, drawableDataMap: CwfResDataMap): Drawable {
|
||||||
val arrow = values().firstOrNull { it.symbol == direction } ?:NONE
|
val arrow = values().firstOrNull { it.symbol == direction } ?: NONE
|
||||||
return arrow.customDrawable?. let {drawableDataMap[arrow.customDrawable.fileName]}?.toDrawable(resources) ?:resources.getDrawable(arrow.icon)
|
return arrow.customDrawable?.let { drawableDataMap[arrow.customDrawable.fileName] }?.toDrawable(resources) ?: resources.getDrawable(arrow.icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -558,7 +567,7 @@ private enum class FontMap(val key: String, var font: Typeface, @FontRes val fon
|
||||||
resDataMap.filter { (_, resData) ->
|
resDataMap.filter { (_, resData) ->
|
||||||
resData.format == ResFormat.TTF || resData.format == ResFormat.OTF
|
resData.format == ResFormat.TTF || resData.format == ResFormat.OTF
|
||||||
}.forEach { (key, resData) ->
|
}.forEach { (key, resData) ->
|
||||||
customFonts[key.lowercase()] = resData.toTypeface() ?:Typeface.DEFAULT
|
customFonts[key.lowercase()] = resData.toTypeface() ?: Typeface.DEFAULT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,16 +7,13 @@ import android.support.wearable.watchface.WatchFaceStyle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.ActivityDigitalstyleBinding
|
import info.nightscout.androidaps.databinding.ActivityDigitalstyleBinding
|
||||||
import info.nightscout.shared.extensions.toVisibility
|
|
||||||
import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
import info.nightscout.androidaps.watchfaces.utils.BaseWatchFace
|
||||||
import info.nightscout.rx.logging.LTag
|
import info.nightscout.rx.logging.LTag
|
||||||
|
|
||||||
|
|
||||||
class DigitalStyleWatchface : BaseWatchFace() {
|
class DigitalStyleWatchface : BaseWatchFace() {
|
||||||
|
|
||||||
private lateinit var binding: ActivityDigitalstyleBinding
|
private lateinit var binding: ActivityDigitalstyleBinding
|
||||||
|
|
|
@ -4,8 +4,8 @@ import android.content.Context
|
||||||
import android.hardware.Sensor
|
import android.hardware.Sensor
|
||||||
import android.hardware.SensorManager
|
import android.hardware.SensorManager
|
||||||
import info.nightscout.rx.AapsSchedulers
|
import info.nightscout.rx.AapsSchedulers
|
||||||
import info.nightscout.rx.logging.AAPSLoggerTest
|
|
||||||
import info.nightscout.rx.weardata.EventData.ActionHeartRate
|
import info.nightscout.rx.weardata.EventData.ActionHeartRate
|
||||||
|
import info.nightscout.sharedtests.AAPSLoggerTest
|
||||||
import io.reactivex.rxjava3.core.Scheduler
|
import io.reactivex.rxjava3.core.Scheduler
|
||||||
import io.reactivex.rxjava3.disposables.Disposable
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
|
@ -22,8 +22,9 @@ import org.mockito.Mockito.`when`
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
internal class HeartRateListenerTest {
|
internal class HeartRateListenerTest {
|
||||||
|
|
||||||
private val aapsLogger = AAPSLoggerTest()
|
private val aapsLogger = AAPSLoggerTest()
|
||||||
private val aapsSchedulers = object: AapsSchedulers {
|
private val aapsSchedulers = object : AapsSchedulers {
|
||||||
override val main: Scheduler = mock(Scheduler::class.java)
|
override val main: Scheduler = mock(Scheduler::class.java)
|
||||||
override val io: Scheduler = mock(Scheduler::class.java)
|
override val io: Scheduler = mock(Scheduler::class.java)
|
||||||
override val cpu: Scheduler = mock(Scheduler::class.java)
|
override val cpu: Scheduler = mock(Scheduler::class.java)
|
||||||
|
@ -35,11 +36,15 @@ internal class HeartRateListenerTest {
|
||||||
|
|
||||||
private fun create(timestampMillis: Long): HeartRateListener {
|
private fun create(timestampMillis: Long): HeartRateListener {
|
||||||
val ctx = mock(Context::class.java)
|
val ctx = mock(Context::class.java)
|
||||||
`when`(aapsSchedulers.io.schedulePeriodicallyDirect(
|
`when`(
|
||||||
any(), eq(60_000L), eq(60_000L), eq(TimeUnit.MILLISECONDS))).thenReturn(schedule)
|
aapsSchedulers.io.schedulePeriodicallyDirect(
|
||||||
|
any(), eq(60_000L), eq(60_000L), eq(TimeUnit.MILLISECONDS)
|
||||||
|
)
|
||||||
|
).thenReturn(schedule)
|
||||||
val listener = HeartRateListener(ctx, aapsLogger, aapsSchedulers, timestampMillis)
|
val listener = HeartRateListener(ctx, aapsLogger, aapsSchedulers, timestampMillis)
|
||||||
verify(aapsSchedulers.io).schedulePeriodicallyDirect(
|
verify(aapsSchedulers.io).schedulePeriodicallyDirect(
|
||||||
any(), eq(60_000L), eq(60_000L), eq(TimeUnit.MILLISECONDS))
|
any(), eq(60_000L), eq(60_000L), eq(TimeUnit.MILLISECONDS)
|
||||||
|
)
|
||||||
listener.sendHeartRate = { hr -> heartRates.add(hr) }
|
listener.sendHeartRate = { hr -> heartRates.add(hr) }
|
||||||
return listener
|
return listener
|
||||||
}
|
}
|
||||||
|
@ -49,10 +54,11 @@ internal class HeartRateListenerTest {
|
||||||
timestamp: Long,
|
timestamp: Long,
|
||||||
heartRate: Int,
|
heartRate: Int,
|
||||||
sensorType: Int? = Sensor.TYPE_HEART_RATE,
|
sensorType: Int? = Sensor.TYPE_HEART_RATE,
|
||||||
accuracy: Int = SensorManager.SENSOR_STATUS_ACCURACY_HIGH) {
|
accuracy: Int = SensorManager.SENSOR_STATUS_ACCURACY_HIGH
|
||||||
|
) {
|
||||||
listener.onSensorChanged(sensorType, accuracy, timestamp, floatArrayOf(heartRate.toFloat()))
|
listener.onSensorChanged(sensorType, accuracy, timestamp, floatArrayOf(heartRate.toFloat()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
fun before() {
|
fun before() {
|
||||||
heartRates.clear()
|
heartRates.clear()
|
||||||
|
@ -66,7 +72,7 @@ internal class HeartRateListenerTest {
|
||||||
Mockito.verifyNoInteractions(aapsSchedulers.newThread)
|
Mockito.verifyNoInteractions(aapsSchedulers.newThread)
|
||||||
verify(schedule).dispose()
|
verify(schedule).dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun onSensorChanged() {
|
fun onSensorChanged() {
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
|
@ -95,7 +101,7 @@ internal class HeartRateListenerTest {
|
||||||
sendSensorEvent(listener, start, 80)
|
sendSensorEvent(listener, start, 80)
|
||||||
assertEquals(0, heartRates.size)
|
assertEquals(0, heartRates.size)
|
||||||
assertEquals(80, listener.currentHeartRateBpm)
|
assertEquals(80, listener.currentHeartRateBpm)
|
||||||
sendSensorEvent(listener, start + d1,100)
|
sendSensorEvent(listener, start + d1, 100)
|
||||||
assertEquals(0, heartRates.size)
|
assertEquals(0, heartRates.size)
|
||||||
assertEquals(100, listener.currentHeartRateBpm)
|
assertEquals(100, listener.currentHeartRateBpm)
|
||||||
|
|
||||||
|
@ -117,7 +123,7 @@ internal class HeartRateListenerTest {
|
||||||
listener.send(start + d1)
|
listener.send(start + d1)
|
||||||
assertEquals(1, heartRates.size)
|
assertEquals(1, heartRates.size)
|
||||||
|
|
||||||
sendSensorEvent(listener, start + d1,100)
|
sendSensorEvent(listener, start + d1, 100)
|
||||||
assertEquals(1, heartRates.size)
|
assertEquals(1, heartRates.size)
|
||||||
listener.send(start + d2)
|
listener.send(start + d2)
|
||||||
assertEquals(2, heartRates.size)
|
assertEquals(2, heartRates.size)
|
||||||
|
|
Loading…
Reference in a new issue