Merge branch 'dev' into ns15

This commit is contained in:
Milos Kozak 2023-01-20 17:04:26 +01:00
commit c1211748d6
20 changed files with 62 additions and 16 deletions

View file

@ -4,7 +4,7 @@ buildscript {
ext { ext {
kotlin_version = '1.8.0' kotlin_version = '1.8.0'
core_version = '1.9.0' core_version = '1.9.0'
rxjava_version = '3.1.5' rxjava_version = '3.1.6'
rxandroid_version = '3.0.2' rxandroid_version = '3.0.2'
rxkotlin_version = '3.0.1' rxkotlin_version = '3.0.1'
room_version = '2.5.0' room_version = '2.5.0'

View file

@ -35,6 +35,6 @@ interface ProfileSource {
var currentProfileIndex: Int var currentProfileIndex: Int
fun currentProfile(): SingleProfile? fun currentProfile(): SingleProfile?
fun storeSettings(activity: FragmentActivity? = null) fun storeSettings(activity: FragmentActivity? = null, emptyCreated: Boolean = false)
} }

View file

@ -16,7 +16,7 @@ interface NsClient : Sync {
fun textLog(): Spanned fun textLog(): Spanned
fun clearLog() fun clearLog()
enum class Collection { ENTRIES, TREATMENTS, FOODS } enum class Collection { ENTRIES, TREATMENTS, FOODS, PROFILE }
/** /**
* NSC v3 does first load of all data * NSC v3 does first load of all data
* next loads are using srvModified property for sync * next loads are using srvModified property for sync

View file

@ -456,6 +456,19 @@ class NSAndroidClientImpl(
} }
override suspend fun getProfileModifiedSince(from: Long): NSAndroidClient.ReadResponse<List<JSONObject>> = callWrapper(dispatcher) {
val response = api.getProfileModifiedSince(from)
if (response.isSuccessful) {
val eTagString = response.headers()["ETag"]
val eTag = eTagString?.substring(3, eTagString.length - 1)?.toLong()
return@callWrapper NSAndroidClient.ReadResponse(code = response.raw().networkResponse?.code ?: response.code(), lastServerModified = eTag, values = response.body()?.result.toNotNull())
} else {
throw UnsuccessfullNightscoutException()
}
}
private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T = private suspend fun <T> callWrapper(dispatcher: CoroutineDispatcher, block: suspend () -> T): T =
withContext(dispatcher) { withContext(dispatcher) {
retry( retry(

View file

@ -35,6 +35,7 @@ interface NSAndroidClient {
suspend fun getDeviceStatusModifiedSince(from: Long): List<NSDeviceStatus> suspend fun getDeviceStatusModifiedSince(from: Long): List<NSDeviceStatus>
suspend fun createProfileStore(remoteProfileStore: JSONObject): CreateUpdateResponse suspend fun createProfileStore(remoteProfileStore: JSONObject): CreateUpdateResponse
suspend fun getProfileModifiedSince(from: Long): ReadResponse<List<JSONObject>>
suspend fun getLastProfileStore(): ReadResponse<List<JSONObject>> suspend fun getLastProfileStore(): ReadResponse<List<JSONObject>>
suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse

View file

@ -93,9 +93,14 @@ internal interface NightscoutRemoteService {
@DELETE("v3/food") @DELETE("v3/food")
suspend fun deleteFood(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun deleteFood(@Path("identifier") identifier: String): Response<NSResponse<RemoteCreateUpdateResponse>>
@GET("v3/profile/history/{from}")
suspend fun getProfileModifiedSince(@Path("from") from: Long, @Query("limit") limit: Long = 10): Response<NSResponse<List<JSONObject>>>
@GET("v3/profile?sort\$desc=date&limit=1") @GET("v3/profile?sort\$desc=date&limit=1")
suspend fun getLastProfile(): Response<NSResponse<List<JSONObject>>> suspend fun getLastProfile(): Response<NSResponse<List<JSONObject>>>
@POST("v3/profile") @POST("v3/profile")
suspend fun createProfile(@Body profile: JsonObject): Response<NSResponse<RemoteCreateUpdateResponse>> suspend fun createProfile(@Body profile: JsonObject): Response<NSResponse<RemoteCreateUpdateResponse>>

View file

@ -22,7 +22,7 @@ dependencies {
implementation project(':app-wear-shared:shared') implementation project(':app-wear-shared:shared')
//Firebase //Firebase
api platform('com.google.firebase:firebase-bom:31.1.1') api platform('com.google.firebase:firebase-bom:31.2.0')
api "com.google.firebase:firebase-analytics-ktx" api "com.google.firebase:firebase-analytics-ktx"
api "com.google.firebase:firebase-crashlytics-ktx" api "com.google.firebase:firebase-crashlytics-ktx"
// StatsActivity not in use now // StatsActivity not in use now

View file

@ -45,7 +45,7 @@ class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JS
} }
override fun getStartDate(): Long { override fun getStartDate(): Long {
val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0 val iso = JsonHelper.safeGetString(data, "created_at") ?: JsonHelper.safeGetString(data, "startDate") ?: return 0
return try { return try {
dateUtil.fromISODateString(iso) dateUtil.fromISODateString(iso)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -45,7 +45,7 @@ class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JS
} }
override fun getStartDate(): Long { override fun getStartDate(): Long {
val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0 val iso = JsonHelper.safeGetString(data, "created_at") ?: JsonHelper.safeGetString(data,"startDate") ?: return 0
return try { return try {
dateUtil.fromISODateString(iso) dateUtil.fromISODateString(iso)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -45,7 +45,7 @@ class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JS
} }
override fun getStartDate(): Long { override fun getStartDate(): Long {
val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0 val iso = JsonHelper.safeGetString(data, "created_at") ?: JsonHelper.safeGetString(data,"startDate") ?: return 0
return try { return try {
dateUtil.fromISODateString(iso) dateUtil.fromISODateString(iso)
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -175,7 +175,7 @@ class ProfilePlugin @Inject constructor(
} }
@Synchronized @Synchronized
override fun storeSettings(activity: FragmentActivity?) { override fun storeSettings(activity: FragmentActivity?, emptyCreated: Boolean) {
for (i in 0 until numOfProfiles) { for (i in 0 until numOfProfiles) {
profiles[i].run { profiles[i].run {
val localProfileNumbered = Constants.LOCAL_PROFILE + "_" + i + "_" val localProfileNumbered = Constants.LOCAL_PROFILE + "_" + i + "_"
@ -191,7 +191,7 @@ class ProfilePlugin @Inject constructor(
} }
sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles) sp.putInt(Constants.LOCAL_PROFILE + "_profiles", numOfProfiles)
sp.putLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, dateUtil.now()) sp.putLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, if (emptyCreated) 0 else dateUtil.now())
createAndStoreConvertedProfile() createAndStoreConvertedProfile()
isEdited = false isEdited = false
aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString()) aapsLogger.debug(LTag.PROFILE, "Storing settings: " + rawProfile?.data.toString())
@ -360,7 +360,7 @@ class ProfilePlugin @Inject constructor(
) )
currentProfileIndex = profiles.size - 1 currentProfileIndex = profiles.size - 1
createAndStoreConvertedProfile() createAndStoreConvertedProfile()
storeSettings() storeSettings(emptyCreated = true)
} }
fun cloneProfile() { fun cloneProfile() {
@ -412,6 +412,7 @@ class ProfilePlugin @Inject constructor(
if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name) if (numOfProfiles > 0) json.put("defaultProfile", currentProfile()?.name)
val startDate = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, dateUtil.now()) val startDate = sp.getLong(info.nightscout.core.utils.R.string.key_local_profile_last_change, dateUtil.now())
json.put("date", startDate) json.put("date", startDate)
json.put("created_at", dateUtil.toISOAsUTC(startDate))
json.put("startDate", dateUtil.toISOAsUTC(startDate)) json.put("startDate", dateUtil.toISOAsUTC(startDate))
json.put("store", store) json.put("store", store)
} catch (e: JSONException) { } catch (e: JSONException) {

View file

@ -132,12 +132,14 @@ class NSClientV3Plugin @Inject constructor(
when { when {
sp.getBoolean(R.string.key_ns_client_paused, false) -> rh.gs(info.nightscout.core.ui.R.string.paused) sp.getBoolean(R.string.key_ns_client_paused, false) -> rh.gs(info.nightscout.core.ui.R.string.paused)
isAllowed.not() -> blockingReason isAllowed.not() -> blockingReason
lastOperationError != null -> rh.gs(info.nightscout.core.ui.R.string.error)
nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected) nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected)
workIsRunning(arrayOf(JOB_NAME)) -> rh.gs(R.string.working) workIsRunning(arrayOf(JOB_NAME)) -> rh.gs(R.string.working)
nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected) nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(info.nightscout.shared.R.string.connected)
nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only) nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only)
else -> rh.gs(info.nightscout.core.ui.R.string.unknown) else -> rh.gs(info.nightscout.core.ui.R.string.unknown)
} }
var lastOperationError: String? = null
internal var nsAndroidClient: NSAndroidClient? = null internal var nsAndroidClient: NSAndroidClient? = null
@ -315,6 +317,7 @@ class NSClientV3Plugin @Inject constructor(
NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L NsClient.Collection.ENTRIES -> lastLoadedSrvModified.collections.entries == 0L
NsClient.Collection.TREATMENTS -> lastLoadedSrvModified.collections.treatments == 0L NsClient.Collection.TREATMENTS -> lastLoadedSrvModified.collections.treatments == 0L
NsClient.Collection.FOODS -> lastLoadedSrvModified.collections.foods == 0L NsClient.Collection.FOODS -> lastLoadedSrvModified.collections.foods == 0L
NsClient.Collection.PROFILE -> lastLoadedSrvModified.collections.profile == 0L
} }
override fun updateLatestBgReceivedIfNewer(latestReceived: Long) { override fun updateLatestBgReceivedIfNewer(latestReceived: Long) {

View file

@ -119,9 +119,11 @@ class LoadBgWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -52,9 +52,11 @@ class LoadDeviceStatusWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -64,9 +64,11 @@ class LoadFoodsWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -28,8 +28,10 @@ class LoadLastModificationWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Error: ", error) aapsLogger.error(LTag.NSCLIENT, "Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -8,6 +8,7 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import info.nightscout.core.utils.receivers.DataWorkerStorage import info.nightscout.core.utils.receivers.DataWorkerStorage
import info.nightscout.core.utils.worker.LoggingWorker import info.nightscout.core.utils.worker.LoggingWorker
import info.nightscout.interfaces.sync.NsClient
import info.nightscout.interfaces.utils.JsonHelper import info.nightscout.interfaces.utils.JsonHelper
import info.nightscout.interfaces.workflow.WorkerClasses import info.nightscout.interfaces.workflow.WorkerClasses
import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin import info.nightscout.plugins.sync.nsclientV3.NSClientV3Plugin
@ -37,13 +38,23 @@ class LoadProfileStoreWorker(
val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null")) val nsAndroidClient = nsClientV3Plugin.nsAndroidClient ?: return Result.failure(workDataOf("Error" to "AndroidClient is null"))
try { try {
val lastLoaded = max(nsClientV3Plugin.lastLoadedSrvModified.collections.profile, 0) val isFirstLoad = nsClientV3Plugin.isFirstLoad(NsClient.Collection.PROFILE)
val lastLoaded = max(nsClientV3Plugin.lastLoadedSrvModified.collections.profile, dateUtil.now() - nsClientV3Plugin.maxAge)
if ((nsClientV3Plugin.newestDataOnServer?.collections?.profile ?: Long.MAX_VALUE) > lastLoaded) { if ((nsClientV3Plugin.newestDataOnServer?.collections?.profile ?: Long.MAX_VALUE) > lastLoaded) {
val response: NSAndroidClient.ReadResponse<List<JSONObject>> = nsAndroidClient.getLastProfileStore() val response: NSAndroidClient.ReadResponse<List<JSONObject>> =
if (isFirstLoad) nsAndroidClient.getLastProfileStore()
else nsAndroidClient.getProfileModifiedSince(lastLoaded)
val profiles = response.values val profiles = response.values
if (profiles.size == 1) { if (profiles.isNotEmpty()) {
val profile = profiles[0] val profile = profiles[profiles.size - 1]
JsonHelper.safeGetLongAllowNull(profile, "srvModified")?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = it } // if srvModified found in response
response.lastServerModified?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = it } ?:
// if srvModified found in record
JsonHelper.safeGetLongAllowNull(profile, "srvModified")?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = it } ?:
// if created_at found in record
JsonHelper.safeGetStringAllowNull(profile, "created_at", null)?.let { nsClientV3Plugin.lastLoadedSrvModified.collections.profile = dateUtil.fromISODateString(it) } ?:
// if not found reset to now
{ nsClientV3Plugin.lastLoadedSrvModified.collections.profile = dateUtil.now() }
nsClientV3Plugin.storeLastLoadedSrvModified() nsClientV3Plugin.storeLastLoadedSrvModified()
aapsLogger.debug(LTag.NSCLIENT, "PROFILE: $profile") aapsLogger.debug(LTag.NSCLIENT, "PROFILE: $profile")
rxBus.send(EventNSClientNewLog("RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}")) rxBus.send(EventNSClientNewLog("RCV", "1 PROFILE from ${dateUtil.dateAndTimeAndSecondsString(lastLoaded)}"))

View file

@ -27,8 +27,10 @@ class LoadStatusWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -104,9 +104,11 @@ class LoadTreatmentsWorker(
} catch (error: Exception) { } catch (error: Exception) {
aapsLogger.error("Error: ", error) aapsLogger.error("Error: ", error)
rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage)) rxBus.send(EventNSClientNewLog("ERROR", error.localizedMessage))
nsClientV3Plugin.lastOperationError = error.localizedMessage
return Result.failure(workDataOf("Error" to error.localizedMessage)) return Result.failure(workDataOf("Error" to error.localizedMessage))
} }
nsClientV3Plugin.lastOperationError = null
return Result.success() return Result.success()
} }
} }

View file

@ -45,7 +45,7 @@ class ProfileStoreObject(val injector: HasAndroidInjector, override val data: JS
} }
override fun getStartDate(): Long { override fun getStartDate(): Long {
val iso = JsonHelper.safeGetString(data, "startDate") ?: return 0 val iso = JsonHelper.safeGetString(data, "created_at") ?: JsonHelper.safeGetString(data, "startDate") ?: return 0
return try { return try {
dateUtil.fromISODateString(iso) dateUtil.fromISODateString(iso)
} catch (e: Exception) { } catch (e: Exception) {