mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-06 11:59:57 +02:00
Fix granting extra time for another day after task completion
This commit is contained in:
parent
c2e83bc11a
commit
cba90b69e3
10 changed files with 122 additions and 23 deletions
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -45,7 +45,7 @@ interface ChildTaskDao {
|
||||||
@Query("SELECT child_task.* FROM child_task JOIN category ON (child_task.category_id = category.id) WHERE category.child_id = :userId")
|
@Query("SELECT child_task.* FROM child_task JOIN category ON (child_task.category_id = category.id) WHERE category.child_id = :userId")
|
||||||
fun getTasksByUserIdSync(userId: String): List<ChildTask>
|
fun getTasksByUserIdSync(userId: String): List<ChildTask>
|
||||||
|
|
||||||
@Query("SELECT child_task.*, category.title as category_title, user.name as child_name FROM child_task JOIN category ON (child_task.category_id = category.id) JOIN user ON (category.child_id = user.id) WHERE child_task.pending_request = 1")
|
@Query("SELECT child_task.*, category.title as category_title, user.name as child_name, user.timezone AS child_timezone FROM child_task JOIN category ON (child_task.category_id = category.id) JOIN user ON (category.child_id = user.id) WHERE child_task.pending_request = 1")
|
||||||
fun getPendingTasks(): LiveData<List<FullChildTask>>
|
fun getPendingTasks(): LiveData<List<FullChildTask>>
|
||||||
|
|
||||||
@Query("SELECT * FROM child_task WHERE category_id = :categoryId")
|
@Query("SELECT * FROM child_task WHERE category_id = :categoryId")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,5 +26,7 @@ data class FullChildTask(
|
||||||
@ColumnInfo(name = "category_title")
|
@ColumnInfo(name = "category_title")
|
||||||
val categoryTitle: String,
|
val categoryTitle: String,
|
||||||
@ColumnInfo(name = "child_name")
|
@ColumnInfo(name = "child_name")
|
||||||
val childName: String
|
val childName: String,
|
||||||
|
@ColumnInfo(name = "child_timezone")
|
||||||
|
val childTimezone: String
|
||||||
)
|
)
|
|
@ -88,6 +88,7 @@ class AppLogic(
|
||||||
val backgroundTaskLogic = BackgroundTaskLogic(this)
|
val backgroundTaskLogic = BackgroundTaskLogic(this)
|
||||||
val appSetupLogic = AppSetupLogic(this)
|
val appSetupLogic = AppSetupLogic(this)
|
||||||
val syncNotificationLogic = SyncNotificationLogic(this)
|
val syncNotificationLogic = SyncNotificationLogic(this)
|
||||||
|
val serverApiLevelLogic = ServerApiLevelLogic(this)
|
||||||
|
|
||||||
private val isConnectedInternal = MutableLiveData<Boolean>().apply { value = false }
|
private val isConnectedInternal = MutableLiveData<Boolean>().apply { value = false }
|
||||||
val isConnected = isConnectedInternal.castDown()
|
val isConnected = isConnectedInternal.castDown()
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package io.timelimit.android.logic
|
||||||
|
|
||||||
|
import io.timelimit.android.livedata.liveDataFromNonNullValue
|
||||||
|
import io.timelimit.android.livedata.map
|
||||||
|
import io.timelimit.android.livedata.switchMap
|
||||||
|
|
||||||
|
class ServerApiLevelLogic(logic: AppLogic) {
|
||||||
|
val infoLive = logic.database.config().getDeviceAuthTokenAsync().switchMap { authToken ->
|
||||||
|
if (authToken.isEmpty())
|
||||||
|
liveDataFromNonNullValue(ServerApiLevelInfo.Offline)
|
||||||
|
else
|
||||||
|
logic.database.config().getServerApiLevelLive().map { apiLevel ->
|
||||||
|
ServerApiLevelInfo.Online(serverLevel = apiLevel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class ServerApiLevelInfo {
|
||||||
|
abstract fun hasLevelOrIsOffline(level: Int): Boolean
|
||||||
|
|
||||||
|
data class Online(val serverLevel: Int): ServerApiLevelInfo() {
|
||||||
|
override fun hasLevelOrIsOffline(level: Int) = serverLevel >= level
|
||||||
|
}
|
||||||
|
|
||||||
|
object Offline: ServerApiLevelInfo() {
|
||||||
|
override fun hasLevelOrIsOffline(level: Int) = true
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1024,16 +1024,18 @@ data class DeleteChildTaskAction(val taskId: String): ParentAction() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ReviewChildTaskAction(val taskId: String, val ok: Boolean, val time: Long): ParentAction() {
|
data class ReviewChildTaskAction(val taskId: String, val ok: Boolean, val time: Long, val day: Int?): ParentAction() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TYPE_VALUE = "REVIEW_CHILD_TASK"
|
private const val TYPE_VALUE = "REVIEW_CHILD_TASK"
|
||||||
private const val TASK_ID = "taskId"
|
private const val TASK_ID = "taskId"
|
||||||
private const val OK = "ok"
|
private const val OK = "ok"
|
||||||
private const val TIME = "time"
|
private const val TIME = "time"
|
||||||
|
private const val DAY = "day"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (time <= 0) throw IllegalArgumentException()
|
if (time <= 0) throw IllegalArgumentException()
|
||||||
|
if (day != null && day < 0) throw IllegalArgumentException()
|
||||||
IdGenerator.assertIdValid(taskId)
|
IdGenerator.assertIdValid(taskId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1045,6 +1047,10 @@ data class ReviewChildTaskAction(val taskId: String, val ok: Boolean, val time:
|
||||||
writer.name(OK).value(ok)
|
writer.name(OK).value(ok)
|
||||||
writer.name(TIME).value(time)
|
writer.name(TIME).value(time)
|
||||||
|
|
||||||
|
if (day != null) {
|
||||||
|
writer.name(DAY).value(day)
|
||||||
|
}
|
||||||
|
|
||||||
writer.endObject()
|
writer.endObject()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -841,11 +841,21 @@ object LocalDatabaseParentActionDispatcher {
|
||||||
if (action.ok) {
|
if (action.ok) {
|
||||||
val category = database.category().getCategoryByIdSync(task.categoryId)!!
|
val category = database.category().getCategoryByIdSync(task.categoryId)!!
|
||||||
|
|
||||||
if (category.extraTimeDay != 0 && category.extraTimeInMillis > 0) {
|
val resetDayBoundExtraTime = category.extraTimeDay != -1 && action.day != null &&
|
||||||
// if the current time is daily, then extend the daily time only
|
category.extraTimeDay != action.day
|
||||||
database.category().updateCategoryExtraTime(categoryId = category.id, extraTimeDay = category.extraTimeDay, newExtraTime = category.extraTimeInMillis + task.extraTimeDuration)
|
|
||||||
|
if (resetDayBoundExtraTime) {
|
||||||
|
database.category().updateCategoryExtraTime(
|
||||||
|
categoryId = category.id,
|
||||||
|
extraTimeDay = -1,
|
||||||
|
newExtraTime = task.extraTimeDuration.toLong()
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
database.category().updateCategoryExtraTime(categoryId = category.id, extraTimeDay = -1, newExtraTime = category.extraTimeInMillis + task.extraTimeDuration)
|
database.category().updateCategoryExtraTime(
|
||||||
|
categoryId = category.id,
|
||||||
|
extraTimeDay = category.extraTimeDay,
|
||||||
|
newExtraTime = category.extraTimeInMillis + task.extraTimeDuration
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
database.childTasks().updateItemSync(task.copy(pendingRequest = false, lastGrantTimestamp = action.time))
|
database.childTasks().updateItemSync(task.copy(pendingRequest = false, lastGrantTimestamp = action.time))
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -27,14 +27,17 @@ import io.timelimit.android.async.Threads
|
||||||
import io.timelimit.android.coroutines.CoroutineFragment
|
import io.timelimit.android.coroutines.CoroutineFragment
|
||||||
import io.timelimit.android.data.model.*
|
import io.timelimit.android.data.model.*
|
||||||
import io.timelimit.android.databinding.FragmentOverviewBinding
|
import io.timelimit.android.databinding.FragmentOverviewBinding
|
||||||
|
import io.timelimit.android.date.DateInTimezone
|
||||||
import io.timelimit.android.livedata.waitForNonNullValue
|
import io.timelimit.android.livedata.waitForNonNullValue
|
||||||
import io.timelimit.android.logic.AppLogic
|
import io.timelimit.android.logic.AppLogic
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import io.timelimit.android.logic.ServerApiLevelInfo
|
||||||
import io.timelimit.android.sync.actions.ReviewChildTaskAction
|
import io.timelimit.android.sync.actions.ReviewChildTaskAction
|
||||||
import io.timelimit.android.ui.main.ActivityViewModel
|
import io.timelimit.android.ui.main.ActivityViewModel
|
||||||
import io.timelimit.android.ui.main.getActivityViewModel
|
import io.timelimit.android.ui.main.getActivityViewModel
|
||||||
import io.timelimit.android.ui.payment.RequiresPurchaseDialogFragment
|
import io.timelimit.android.ui.payment.RequiresPurchaseDialogFragment
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class OverviewFragment : CoroutineFragment() {
|
class OverviewFragment : CoroutineFragment() {
|
||||||
private val handlers: OverviewFragmentParentHandlers by lazy { parentFragment as OverviewFragmentParentHandlers }
|
private val handlers: OverviewFragmentParentHandlers by lazy { parentFragment as OverviewFragmentParentHandlers }
|
||||||
|
@ -97,13 +100,17 @@ class OverviewFragment : CoroutineFragment() {
|
||||||
model.showMoreDevices(level)
|
model.showMoreDevices(level)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTaskConfirmed(task: ChildTask, hasPremium: Boolean) {
|
override fun onTaskConfirmed(task: ChildTask, hasPremium: Boolean, timezone: TimeZone, serverApiLevel: ServerApiLevelInfo) {
|
||||||
if (hasPremium) {
|
if (hasPremium) {
|
||||||
|
val time = logic.timeApi.getCurrentTimeInMillis()
|
||||||
|
val day = DateInTimezone.newInstance(time, timezone).dayOfEpoch
|
||||||
|
|
||||||
auth.tryDispatchParentAction(
|
auth.tryDispatchParentAction(
|
||||||
ReviewChildTaskAction(
|
ReviewChildTaskAction(
|
||||||
taskId = task.taskId,
|
taskId = task.taskId,
|
||||||
ok = true,
|
ok = true,
|
||||||
time = logic.timeApi.getCurrentTimeInMillis()
|
time = time,
|
||||||
|
day = if (serverApiLevel.hasLevelOrIsOffline(2)) day else null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else RequiresPurchaseDialogFragment().show(parentFragmentManager)
|
} else RequiresPurchaseDialogFragment().show(parentFragmentManager)
|
||||||
|
@ -114,7 +121,8 @@ class OverviewFragment : CoroutineFragment() {
|
||||||
ReviewChildTaskAction(
|
ReviewChildTaskAction(
|
||||||
taskId = task.taskId,
|
taskId = task.taskId,
|
||||||
ok = false,
|
ok = false,
|
||||||
time = logic.timeApi.getCurrentTimeInMillis()
|
time = logic.timeApi.getCurrentTimeInMillis(),
|
||||||
|
day = null
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,8 +26,10 @@ import io.timelimit.android.data.model.Device
|
||||||
import io.timelimit.android.data.model.User
|
import io.timelimit.android.data.model.User
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.databinding.*
|
import io.timelimit.android.databinding.*
|
||||||
|
import io.timelimit.android.logic.ServerApiLevelInfo
|
||||||
import io.timelimit.android.ui.util.DateUtil
|
import io.timelimit.android.ui.util.DateUtil
|
||||||
import io.timelimit.android.util.TimeTextUtil
|
import io.timelimit.android.util.TimeTextUtil
|
||||||
|
import java.util.*
|
||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
class OverviewFragmentAdapter : RecyclerView.Adapter<OverviewFragmentViewHolder>() {
|
class OverviewFragmentAdapter : RecyclerView.Adapter<OverviewFragmentViewHolder>() {
|
||||||
|
@ -260,7 +262,15 @@ class OverviewFragmentAdapter : RecyclerView.Adapter<OverviewFragmentViewHolder>
|
||||||
it.lastGrant = if (item.task.lastGrantTimestamp == 0L) null else DateUtil.formatAbsoluteDate(it.root.context, item.task.lastGrantTimestamp)
|
it.lastGrant = if (item.task.lastGrantTimestamp == 0L) null else DateUtil.formatAbsoluteDate(it.root.context, item.task.lastGrantTimestamp)
|
||||||
it.taskTitle = item.task.taskTitle
|
it.taskTitle = item.task.taskTitle
|
||||||
|
|
||||||
it.yesButton.setOnClickListener { handlers?.onTaskConfirmed(task = item.task, hasPremium = item.hasPremium) }
|
it.yesButton.setOnClickListener {
|
||||||
|
handlers?.onTaskConfirmed(
|
||||||
|
task = item.task,
|
||||||
|
hasPremium = item.hasPremium,
|
||||||
|
timezone = item.childTimezone,
|
||||||
|
serverApiLevel = item.serverApiLevel
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
it.noButton.setOnClickListener { handlers?.onTaskRejected(item.task) }
|
it.noButton.setOnClickListener { handlers?.onTaskRejected(item.task) }
|
||||||
it.skipButton.setOnClickListener { handlers?.onSkipTaskReviewClicked(item.task) }
|
it.skipButton.setOnClickListener { handlers?.onSkipTaskReviewClicked(item.task) }
|
||||||
}
|
}
|
||||||
|
@ -305,6 +315,6 @@ interface OverviewFragmentHandlers {
|
||||||
fun onShowAllUsersClicked()
|
fun onShowAllUsersClicked()
|
||||||
fun onSetDeviceListVisibility(level: DeviceListItemVisibility)
|
fun onSetDeviceListVisibility(level: DeviceListItemVisibility)
|
||||||
fun onSkipTaskReviewClicked(task: ChildTask)
|
fun onSkipTaskReviewClicked(task: ChildTask)
|
||||||
fun onTaskConfirmed(task: ChildTask, hasPremium: Boolean)
|
fun onTaskConfirmed(task: ChildTask, hasPremium: Boolean, timezone: TimeZone, serverApiLevel: ServerApiLevelInfo)
|
||||||
fun onTaskRejected(task: ChildTask)
|
fun onTaskRejected(task: ChildTask)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -20,6 +20,8 @@ import io.timelimit.android.data.model.Device
|
||||||
import io.timelimit.android.data.model.User
|
import io.timelimit.android.data.model.User
|
||||||
import io.timelimit.android.data.model.UserType
|
import io.timelimit.android.data.model.UserType
|
||||||
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
||||||
|
import io.timelimit.android.logic.ServerApiLevelInfo
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
sealed class OverviewFragmentItem
|
sealed class OverviewFragmentItem
|
||||||
object OverviewFragmentHeaderUsers: OverviewFragmentItem()
|
object OverviewFragmentHeaderUsers: OverviewFragmentItem()
|
||||||
|
@ -41,4 +43,11 @@ sealed class ShowMoreOverviewFragmentItem: OverviewFragmentItem() {
|
||||||
object ShowAllUsers: ShowMoreOverviewFragmentItem()
|
object ShowAllUsers: ShowMoreOverviewFragmentItem()
|
||||||
data class ShowMoreDevices(val level: DeviceListItemVisibility): ShowMoreOverviewFragmentItem()
|
data class ShowMoreDevices(val level: DeviceListItemVisibility): ShowMoreOverviewFragmentItem()
|
||||||
}
|
}
|
||||||
data class TaskReviewOverviewItem(val task: ChildTask, val childTitle: String, val categoryTitle: String, val hasPremium: Boolean): OverviewFragmentItem()
|
data class TaskReviewOverviewItem(
|
||||||
|
val task: ChildTask,
|
||||||
|
val childTitle: String,
|
||||||
|
val categoryTitle: String,
|
||||||
|
val hasPremium: Boolean,
|
||||||
|
val childTimezone: TimeZone,
|
||||||
|
val serverApiLevel: ServerApiLevelInfo
|
||||||
|
): OverviewFragmentItem()
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* TimeLimit Copyright <C> 2019 - 2021 Jonas Lochmann
|
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -26,6 +26,7 @@ import io.timelimit.android.livedata.liveDataFromFunction
|
||||||
import io.timelimit.android.livedata.map
|
import io.timelimit.android.livedata.map
|
||||||
import io.timelimit.android.livedata.switchMap
|
import io.timelimit.android.livedata.switchMap
|
||||||
import io.timelimit.android.logic.DefaultAppLogic
|
import io.timelimit.android.logic.DefaultAppLogic
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
class OverviewFragmentModel(application: Application): AndroidViewModel(application) {
|
class OverviewFragmentModel(application: Application): AndroidViewModel(application) {
|
||||||
private val logic = DefaultAppLogic.with(application)
|
private val logic = DefaultAppLogic.with(application)
|
||||||
|
@ -124,9 +125,18 @@ class OverviewFragmentModel(application: Application): AndroidViewModel(applicat
|
||||||
}
|
}
|
||||||
private val hasPremiumLive = logic.fullVersion.shouldProvideFullVersionFunctions
|
private val hasPremiumLive = logic.fullVersion.shouldProvideFullVersionFunctions
|
||||||
private val pendingTaskItemLive = hasPremiumLive.switchMap { hasPremium ->
|
private val pendingTaskItemLive = hasPremiumLive.switchMap { hasPremium ->
|
||||||
pendingTasksToShowLive.map { tasks ->
|
logic.serverApiLevelLogic.infoLive.switchMap { serverApiLevel ->
|
||||||
tasks.firstOrNull()?.let {
|
pendingTasksToShowLive.map { tasks ->
|
||||||
TaskReviewOverviewItem(task = it.childTask, childTitle = it.childName, categoryTitle = it.categoryTitle, hasPremium = hasPremium)
|
tasks.firstOrNull()?.let {
|
||||||
|
TaskReviewOverviewItem(
|
||||||
|
task = it.childTask,
|
||||||
|
childTitle = it.childName,
|
||||||
|
categoryTitle = it.categoryTitle,
|
||||||
|
hasPremium = hasPremium,
|
||||||
|
childTimezone = TimeZone.getTimeZone(it.childTimezone),
|
||||||
|
serverApiLevel = serverApiLevel
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue