diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt
index 90aa98ec..49b24503 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt
@@ -58,6 +58,10 @@ const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcz
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
const val IDZIENNIK_WEB_MESSAGES_LIST = "mod_komunikator/WS_wiadomosci.asmx/PobierzListeWiadomosci"
+val IDZIENNIK_API_USER_AGENT = SYSTEM_USER_AGENT
+const val IDZIENNIK_API_URL = "https://iuczniowie.progman.pl/idziennik/api"
+const val IDZIENNIK_API_CURRENT_REGISTER = "Uczniowie/\$STUDENT_ID/AktualnyDziennik"
+
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT
const val VULCAN_API_USER_AGENT = "MobileUserAgent"
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt
index ae9db1e7..f1f3564c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt
@@ -133,7 +133,6 @@ const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
const val ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 403
const val ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE = 404
const val ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR = 405
-const val ERROR_LOGIN_IDZIENNIK_WEB_API_ERROR = 406 /* {"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""} */
const val ERROR_LOGIN_IDZIENNIK_WEB_OTHER = 410
const val ERROR_LOGIN_IDZIENNIK_WEB_API_NO_ACCESS = 411 /* {"d":{"__type":"mds.Web.mod_komunikator.WS_mod_wiadomosci+detailWiadomosci","Wiadomosc":{"_recordId":0,"DataNadania":null,"DataOdczytania":null,"Nadawca":null,"ListaOdbiorcow":[],"Tytul":null,"Text":null,"ListaZal":[]},"Bledy":{"__type":"mds.Module.Globalne+sBledy","CzyJestBlad":true,"ListaBledow":["Nie masz dostępu do tych zasobów!"],"ListaKodowBledow":[]},"czyJestWiecej":false}} */
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION = 420
@@ -146,6 +145,8 @@ const val ERROR_IDZIENNIK_WEB_SERVER_ERROR = 433
const val ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 434
const val ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR = 440
const val ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA = 441
+const val ERROR_IDZIENNIK_API_ACCESS_DENIED = 450
+const val ERROR_IDZIENNIK_API_OTHER = 451
const val ERROR_TEMPLATE_WEB_OTHER = 801
@@ -160,3 +161,4 @@ const val EXCEPTION_NOTIFY_AND_SYNC = 910
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
+const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt
index a35d95ba..532d021b 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt
@@ -40,24 +40,24 @@ object Regexes {
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
- "".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
val IDZIENNIK_LOGIN_ERROR by lazy {
- "id=\"spanErrorMessage\">(.*?)".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """id="spanErrorMessage">(.*?)""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
- "Imię i nazwisko:.+?\">(.+?)".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """Imię i nazwisko:.+?">(.+?)""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
- "id=\"ctl00_CzyRodzic\" value=\"([01])\" />".toRegex()
+ """id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
}
val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
- "name=\"ctl00\\\$dxComboRokSzkolny\".+?selected=\"selected\".*?value=\"([0-9]+)\">([0-9/]+)<".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9/]+)<""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
- "".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
- "(.+?)\\s(.+?)\\s*\\((.+?),\\s*(.+?)\\)".toRegex(RegexOption.DOT_MATCHES_ALL)
+ """(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)""".toRegex(RegexOption.DOT_MATCHES_ALL)
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt
index 61629c3d..a774129d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt
@@ -18,7 +18,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
fun isWebLoginValid() = loginExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty() && webAuth.isNotNullNorEmpty()
- fun isApiLoginValid() = loginExpiryTime-30 > currentTimeUnix() && apiBearer.isNotNullNorEmpty()
+ fun isApiLoginValid() = apiExpiryTime-30 > currentTimeUnix() && apiBearer.isNotNullNorEmpty()
override fun satisfyLoginMethods() {
loginMethods.clear()
@@ -46,6 +46,11 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
get() { mLoginExpiryTime = mLoginExpiryTime ?: loginStore.getLoginData("loginExpiryTime", 0L); return mLoginExpiryTime ?: 0L }
set(value) { loginStore.putLoginData("loginExpiryTime", value); mLoginExpiryTime = value }
+ private var mApiExpiryTime: Long? = null
+ var apiExpiryTime: Long
+ get() { mApiExpiryTime = mApiExpiryTime ?: loginStore.getLoginData("apiExpiryTime", 0L); return mApiExpiryTime ?: 0L }
+ set(value) { loginStore.putLoginData("apiExpiryTime", value); mApiExpiryTime = value }
+
/* __ __ _
\ \ / / | |
\ \ /\ / /__| |__
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt
new file mode 100644
index 00000000..66a87dfa
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-29.
+ */
+
+package pl.szczodrzynski.edziennik.api.v2.idziennik.data
+
+import com.google.gson.JsonArray
+import com.google.gson.JsonElement
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+import im.wangchao.mhttp.Request
+import im.wangchao.mhttp.Response
+import im.wangchao.mhttp.callback.TextCallbackHandler
+import pl.szczodrzynski.edziennik.api.v2.*
+import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.api.v2.models.ApiError
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.utils.Utils
+import java.net.HttpURLConnection
+
+open class IdziennikApi(open val data: DataIdziennik) {
+ companion object {
+ const val TAG = "IdziennikApi"
+ }
+
+ val profileId
+ get() = data.profile?.id ?: -1
+
+ val profile
+ get() = data.profile
+
+ fun apiGet(tag: String, endpointTemplate: String, method: Int = GET, parameters: Map = emptyMap(), onSuccess: (json: JsonElement) -> Unit) {
+ val endpoint = endpointTemplate.replace("\$STUDENT_ID", data.studentId ?: "")
+ Utils.d(tag, "Request: Idziennik/API - $IDZIENNIK_API_URL/$endpoint")
+
+ val callback = object : TextCallbackHandler() {
+ override fun onSuccess(text: String?, response: Response?) {
+ if (text == null) {
+ data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
+ .withResponse(response))
+ return
+ }
+
+ val json = try {
+ JsonParser().parse(text)
+ } catch (_: Exception) { null }
+
+ var error: String? = null
+ if (json == null) {
+ error = text
+ }
+ else if (json is JsonObject) {
+ error = if (response?.code() == 200) null else
+ json.getString("message") ?: json.toString()
+ }
+ error?.let { code ->
+ when (code) {
+ "Authorization has been denied for this request." -> ERROR_IDZIENNIK_API_ACCESS_DENIED
+ else -> ERROR_IDZIENNIK_API_OTHER
+ }.let { errorCode ->
+ data.error(ApiError(tag, errorCode)
+ .withApiResponse(text)
+ .withResponse(response))
+ return
+ }
+ }
+
+ try {
+ onSuccess(json!!)
+ } catch (e: Exception) {
+ data.error(ApiError(tag, EXCEPTION_IDZIENNIK_API_REQUEST)
+ .withResponse(response)
+ .withThrowable(e)
+ .withApiResponse(text))
+ }
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ Request.builder()
+ .url("$IDZIENNIK_API_URL/$endpoint")
+ .userAgent(IDZIENNIK_API_USER_AGENT)
+ .addHeader("Authorization", "Bearer ${data.apiBearer}")
+ .apply {
+ when (method) {
+ GET -> get()
+ POST -> {
+ postJson()
+ val json = JsonObject()
+ parameters.map { (name, value) ->
+ when (value) {
+ is JsonObject -> json.add(name, value)
+ is JsonArray -> json.add(name, value)
+ is String -> json.addProperty(name, value)
+ is Int -> json.addProperty(name, value)
+ is Long -> json.addProperty(name, value)
+ is Float -> json.addProperty(name, value)
+ is Char -> json.addProperty(name, value)
+ }
+ }
+ setJsonBody(json)
+ }
+ }
+ }
+ .allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
+ .allowErrorCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt
index 8a78e6ee..4f3b3e66 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt
@@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.api.v2.idziennik.data
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.api.v2.idziennik.*
+import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiCurrentRegister
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.web.*
import pl.szczodrzynski.edziennik.utils.Utils
@@ -65,6 +66,10 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
IdziennikWebAttendance(data) { onSuccess() }
}
+ ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
+ IdziennikApiCurrentRegister(data) { onSuccess() }
+ }
else -> onSuccess()
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt
new file mode 100644
index 00000000..2366e625
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-29.
+ */
+
+package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.DAY
+import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_CURRENT_REGISTER
+import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
+import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
+import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
+import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
+import pl.szczodrzynski.edziennik.getInt
+import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.utils.models.Date
+import pl.szczodrzynski.edziennik.utils.models.Time
+
+class IdziennikApiCurrentRegister(override val data: DataIdziennik,
+ val onSuccess: () -> Unit) : IdziennikApi(data) {
+ companion object {
+ private const val TAG = "IdziennikApiCurrentRegister"
+ }
+
+ init {
+ data.profile?.luckyNumber = -1
+ data.profile?.luckyNumberDate = null
+
+ apiGet(TAG, IDZIENNIK_API_CURRENT_REGISTER) { json ->
+ if (json !is JsonObject) {
+ onSuccess()
+ return@apiGet
+ }
+
+ var nextSync = System.currentTimeMillis() + 14*DAY*1000
+
+ val settings = json.getJsonObject("ustawienia")?.apply {
+ profile?.dateSemester1Start = getString("poczatekSemestru1")?.let { Date.fromY_m_d(it) }
+ profile?.dateSemester2Start = getString("koniecSemestru1")?.let { Date.fromY_m_d(it).stepForward(0, 0, 1) }
+ profile?.dateYearEnd = getString("koniecSemestru2")?.let { Date.fromY_m_d(it) }
+ }
+
+ json.getInt("szczesliwyNumerek")?.let { luckyNumber ->
+ val luckyNumberDate = Date.getToday()
+ settings.getString("godzinaPublikacjiSzczesliwegoLosu")
+ ?.let { Time.fromH_m(it) }
+ ?.let { publishTime ->
+ val now = Time.getNow()
+ if (publishTime.value < 150000 && now.value < publishTime.value) {
+ nextSync = luckyNumberDate.combineWith(publishTime)
+ luckyNumberDate.stepForward(0, 0, -1) // the lucky number is still for yesterday
+ }
+ else if (publishTime.value >= 150000 && now.value > publishTime.value) {
+ luckyNumberDate.stepForward(0, 0, 1) // the lucky number is already for tomorrow
+ nextSync = luckyNumberDate.combineWith(publishTime)
+ }
+ else if (publishTime.value < 150000) {
+ nextSync = luckyNumberDate
+ .clone()
+ .stepForward(0, 0, 1)
+ .combineWith(publishTime)
+ }
+ else {
+ nextSync = luckyNumberDate.combineWith(publishTime)
+ }
+ }
+
+
+ val luckyNumberObject = LuckyNumber(
+ data.profileId,
+ Date.getToday(),
+ luckyNumber
+ )
+
+ data.luckyNumberList.add(luckyNumberObject)
+ data.metadataList.add(
+ Metadata(
+ profileId,
+ Metadata.TYPE_LUCKY_NUMBER,
+ luckyNumberObject.date.value.toLong(),
+ data.profile?.empty ?: false,
+ data.profile?.empty ?: false,
+ System.currentTimeMillis()
+ ))
+ }
+
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER, syncAt = nextSync)
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebAttendance.kt
index 68823c17..1bcbddac 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebAttendance.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebAttendance.kt
@@ -25,13 +25,14 @@ class IdziennikWebAttendance(override val data: DataIdziennik,
private const val TAG = "IdziennikWebAttendance"
}
+ private var attendanceYear = Date.getToday().year
+ private var attendanceMonth = Date.getToday().month
+ private var attendancePrevMonthChecked = false
+
init {
getAttendance()
}
- private var attendanceYear: Int = Date.getToday().year
- private var attendanceMonth: Int = Date.getToday().month
- private var attendancePrevMonthChecked = false
private fun getAttendance() {
webApiGet(TAG, IDZIENNIK_WEB_ATTENDANCE, mapOf(
"idPozDziennika" to data.registerId,
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebExams.kt
index eb0e2c0e..3a9a3982 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebExams.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebExams.kt
@@ -24,14 +24,15 @@ class IdziennikWebExams(override val data: DataIdziennik,
private const val TAG = "IdziennikWebExams"
}
- init {
- getExams()
- }
-
private var examsYear = Date.getToday().year
private var examsMonth = Date.getToday().month
private var examsMonthsChecked = 0
private var examsNextMonthChecked = false // TO DO temporary // no more // idk
+
+ init {
+ getExams()
+ }
+
private fun getExams() {
val param = JsonObject()
param.addProperty("strona", 1)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt
index 775200c6..85f9af55 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt
@@ -8,6 +8,8 @@ import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler
import okhttp3.Cookie
+import pl.szczodrzynski.edziennik.HOUR
+import pl.szczodrzynski.edziennik.MINUTE
import pl.szczodrzynski.edziennik.api.v2.*
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
@@ -65,7 +67,8 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
data.webSessionId = cookies.singleOrNull { it.name() == "ASP.NET_SessionId_iDziennik" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
data.webAuth = cookies.singleOrNull { it.name() == ".ASPXAUTH" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
data.apiBearer = cookies.singleOrNull { it.name() == "Bearer" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
- data.loginExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
+ data.loginExpiryTime = response.getUnixDate() + 45 * MINUTE
+ data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */
return@run null
}?.let { errorCode ->
data.error(ApiError(TAG, errorCode)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt
index ed4a50b7..bd38d628 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt
@@ -324,7 +324,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
}
}
- fun setSyncNext(endpointId: Int, syncIn: Long? = null, viewId: Int? = null) {
+ fun setSyncNext(endpointId: Int, syncIn: Long? = null, viewId: Int? = null, syncAt: Long? = null) {
EndpointTimer(profile?.id ?: -1, endpointId).apply {
syncedNow()
@@ -334,6 +334,9 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
else
syncIn(syncIn)
}
+ if (syncAt != null) {
+ nextSync = syncAt
+ }
if (viewId != null)
syncWhenView(viewId)