diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java b/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java index 553d68f81..860c8de38 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/GSonFactoryCreator.java @@ -6,6 +6,8 @@ import com.google.gson.reflect.TypeToken; import com.habitrpg.android.habitica.models.Achievement; import com.habitrpg.android.habitica.models.ContentResult; import com.habitrpg.android.habitica.models.FAQArticle; +import com.habitrpg.android.habitica.models.tasks.GroupAssignedDetails; +import com.habitrpg.android.habitica.utils.AssignedDetailsDeserializer; import com.habitrpg.common.habitica.models.Notification; import com.habitrpg.android.habitica.models.Skill; import com.habitrpg.android.habitica.models.Tag; @@ -101,6 +103,8 @@ public class GSonFactoryCreator { }.getType(); Type achievementsListType = new TypeToken>() { }.getType(); + Type assignedDetailsListType = new TypeToken>() { + }.getType(); return new GsonBuilder() .registerTypeAdapter(taskTagClassListType, new TaskTagDeserializer()) @@ -129,6 +133,7 @@ public class GSonFactoryCreator { .registerTypeAdapter(ownedPetListType, new OwnedPetListDeserializer()) .registerTypeAdapter(ownedMountListType, new OwnedMountListDeserializer()) .registerTypeAdapter(achievementsListType, new AchievementListDeserializer()) + .registerTypeAdapter(assignedDetailsListType, new AssignedDetailsDeserializer()) .registerTypeAdapter(Quest.class, new QuestDeserializer()) .registerTypeAdapter(Member.class, new MemberSerialization()) .registerTypeAdapter(WorldState.class, new WorldStateSerialization()) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt index c9788bd3a..325f16dba 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/Task.kt @@ -117,6 +117,19 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask { val completedChecklistCount: Int get() = checklist?.count { it.completed } ?: 0 + fun completed(byUserID: String?): Boolean { + return if (isGroupTask) { + group?.assignedUsersDetail?.firstOrNull { it.assignedUserID == byUserID }?.completed ?: false + } else { + completed + } + } + + fun isDisplayedActiveForUser(userID: String?): Boolean { + val isActive = ((isDue == true && type == TaskType.DAILY) || type == TaskType.TODO) + return isActive && completed(userID) + } + val streakString: String? get() { return if (counterUp != null && (counterUp ?: 0) > 0 && counterDown != null && (counterDown ?: 0) > 0) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.kt index 49e2191da..2e936526c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskGroupPlan.kt @@ -7,6 +7,15 @@ import io.realm.RealmObject import io.realm.annotations.RealmClass import java.util.Date +@RealmClass(embedded = true) +open class GroupAssignedDetails: RealmObject(), BaseObject { + var assignedDate: String? = null + var assignedUsername: String? = null + var assignedUserID: String? = null + var assigningUsername: String? = null + var completed: Boolean = false +} + @RealmClass(embedded = true) open class TaskGroupPlan : RealmObject(), BaseObject { @@ -17,6 +26,7 @@ open class TaskGroupPlan : RealmObject(), BaseObject { var assignedDate: Date? = null var assigningUsername: String? = null var assignedUsers: RealmList = RealmList() + var assignedUsersDetail: RealmList = RealmList() var approvalRequested: Boolean? = false var approvalApproved: Boolean? = false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt index e39b19af2..801e10a1c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt @@ -79,6 +79,7 @@ abstract class RealmBaseTasksRecyclerViewAdapter( override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val item = getItem(position) if (item != null && holder is BaseTaskViewHolder) { + holder.userID = user?.id holder.isLocked = !viewModel.canScoreTask(item) holder.bind(item, position, taskDisplayMode, viewModel.ownerID.value) holder.errorButtonClicked = Action { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt index 42ef8c45a..1af36d06d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt @@ -43,6 +43,7 @@ abstract class BaseTaskViewHolder constructor( var task: Task? = null var movingFromPosition: Int? = null var errorButtonClicked: Action? = null + var userID: String? = null var isLocked = false protected var context: Context private val mainTaskWrapper: ViewGroup = itemView.findViewById(R.id.main_task_wrapper) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt index 58b3a27ad..499445b24 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt @@ -56,7 +56,7 @@ abstract class ChecklistedViewHolder( displayMode: String, ownerID: String? ) { - var completed = data.completed + var completed = data.completed(userID) if (data.isPendingApproval) { completed = false } @@ -80,11 +80,11 @@ abstract class ChecklistedViewHolder( val regularBoxBackground = if (task?.type == TaskType.DAILY) R.drawable.daily_unchecked else R.drawable.todo_unchecked val completedBoxBackground = if (task?.type == TaskType.DAILY) R.drawable.daily_checked else R.drawable.todo_checked val inactiveBoxBackground = R.drawable.daily_inactive - if (this.shouldDisplayAsActive(data) && !data.isPendingApproval) { + if (this.shouldDisplayAsActive(data, userID) && !data.isPendingApproval) { this.checkboxHolder.setBackgroundResource(data.lightTaskColor) checkboxBackground.setBackgroundResource(regularBoxBackground) } else { - if (data.completed) { + if (completed) { titleTextView.setTextColor(ContextCompat.getColor(context, R.color.text_quad)) notesTextView?.setTextColor(ContextCompat.getColor(context, R.color.text_quad)) this.checkboxHolder.setBackgroundColor(context.getThemeColor(R.attr.colorWindowBackground)) @@ -98,7 +98,7 @@ abstract class ChecklistedViewHolder( } } - abstract fun shouldDisplayAsActive(newTask: Task?): Boolean + abstract fun shouldDisplayAsActive(task: Task?, userID: String?): Boolean private fun updateChecklistDisplay() { // This needs to be a LinearLayout, as ListViews can not be inside other ListViews. @@ -116,7 +116,7 @@ abstract class ChecklistedViewHolder( context, ( if (context.isUsingNightModeResources()) { - if (task?.completed == true || (task?.type == TaskType.DAILY && task?.isDue == false)) { + if (task?.completed(userID) == true || (task?.type == TaskType.DAILY && task?.isDue == false)) { R.color.checkbox_fill } else { task?.lightTaskColor @@ -151,7 +151,7 @@ abstract class ChecklistedViewHolder( } val color = ContextCompat.getColor( context, - if (task?.completed == true || (task?.type == TaskType.DAILY && task?.isDue == false)) { + if (task?.completed(userID) == true || (task?.type == TaskType.DAILY && task?.isDue == false)) { checkmark?.drawable?.setTint(ContextCompat.getColor(context, R.color.text_dimmed)) R.color.offset_background } else { @@ -207,7 +207,7 @@ abstract class ChecklistedViewHolder( override fun onLeftActionTouched() { super.onLeftActionTouched() if (task?.isValid == true) { - onCheckedChanged(!(task?.completed ?: false)) + onCheckedChanged(!(task?.completed(userID) ?: false)) } } @@ -224,8 +224,8 @@ abstract class ChecklistedViewHolder( if (task?.isValid != true) { return } - if (isChecked != task?.completed) { - task?.let { scoreTaskFunc(it, if (task?.completed == false) TaskDirection.UP else TaskDirection.DOWN) } + if (isChecked != task?.completed(userID)) { + task?.let { scoreTaskFunc(it, if (task?.completed(userID) == false) TaskDirection.UP else TaskDirection.DOWN) } } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt index 04a2147aa..3ff7784bf 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt @@ -1,7 +1,6 @@ package com.habitrpg.android.habitica.ui.viewHolders.tasks import android.view.View -import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider import com.habitrpg.android.habitica.models.tasks.ChecklistItem import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.shared.habitica.models.responses.TaskDirection @@ -69,8 +68,8 @@ class DailyViewHolder( super.bind(data, position, displayMode, ownerID) } - override fun shouldDisplayAsActive(newTask: Task?): Boolean { - return newTask?.isDisplayedActive ?: false + override fun shouldDisplayAsActive(task: Task?, userID: String?): Boolean { + return task?.isDisplayedActive ?: false } override fun configureSpecialTaskTextView(task: Task) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt index 2370a4ad4..8ac863f50 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt @@ -42,7 +42,7 @@ class TodoViewHolder( } } - override fun shouldDisplayAsActive(newTask: Task?): Boolean { - return newTask?.completed != true + override fun shouldDisplayAsActive(task: Task?, userID: String?): Boolean { + return task?.completed(userID) != true } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/AssignedDetailsDeserializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/AssignedDetailsDeserializer.kt new file mode 100644 index 000000000..9adef8c45 --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/AssignedDetailsDeserializer.kt @@ -0,0 +1,31 @@ +package com.habitrpg.android.habitica.utils + +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import com.habitrpg.android.habitica.models.tasks.GroupAssignedDetails +import io.realm.RealmList +import java.lang.reflect.Type + +class AssignedDetailsDeserializer: JsonDeserializer> { + override fun deserialize( + json: JsonElement?, + typeOfT: Type?, + context: JsonDeserializationContext? + ): RealmList { + val list = RealmList() + if (json == null) { + return list + } else if (json.isJsonArray) { + json.asJsonArray.forEach { list.add(context?.deserialize(it, GroupAssignedDetails::class.java)) } + } else { + val jsonObject = json.asJsonObject + jsonObject.keySet().forEach { + val details= context?.deserialize(jsonObject[it], GroupAssignedDetails::class.java) + details?.assignedUserID = it + list.add(details) + } + } + return list + } +} \ No newline at end of file