diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 50125ea84..5621d5174 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -265,10 +265,9 @@
You purchased a reward
World Quest
Need a break? Check into Daniel’s Inn to pause some of Habitica’s more difficult game mechanics:\n\n
-• Missed Dailies won’t damage you\n
-• Tasks won’t lose streaks or decay in color\n
-• Bosses won’t do damage for your missed Dailies\n
-• Your boss damage or collection quest items will stay pending until check-out
+• Your missed Dailies won\'t damage you (bosses will still do damage caused by other Party member\'s missed Dailies)
+• Your Task streaks and Habit counters will not reset
+• Your damage to the Quest boss or found collection items will remain pending until you check out of the Inn
You don\'t have any %s
Lvl %1$d %2$s
Level %1$d %2$s
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
index 99ca776a5..b6df6db47 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
@@ -2,12 +2,12 @@ package com.habitrpg.android.habitica.data
import com.habitrpg.android.habitica.models.BaseMainObject
import com.habitrpg.android.habitica.models.responses.BulkTaskScoringData
-import com.habitrpg.common.habitica.models.responses.TaskScoringResult
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.models.tasks.TaskList
+import com.habitrpg.android.habitica.models.user.User
+import com.habitrpg.common.habitica.models.responses.TaskScoringResult
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.common.habitica.models.tasks.TasksOrder
-import com.habitrpg.android.habitica.models.user.User
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Single
@@ -15,8 +15,8 @@ import kotlinx.coroutines.flow.Flow
import java.util.Date
interface TaskRepository : BaseRepository {
- fun getTasks(taskType: TaskType, userID: String? = null): Flow>
- fun getTasksFlowable(taskType: TaskType, userID: String? = null): Flowable>
+ fun getTasks(taskType: TaskType, userID: String? = null, includedGroupIDs: Array): Flow>
+ fun getTasksFlowable(taskType: TaskType, userID: String? = null, includedGroupIDs: Array): Flowable>
fun saveTasks(userId: String, order: TasksOrder, tasks: TaskList)
fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
index 66fe6a6ed..4822e1ced 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
@@ -39,11 +39,11 @@ class TaskRepositoryImpl(
) : BaseRepositoryImpl(localRepository, apiClient, userID), TaskRepository {
private var lastTaskAction: Long = 0
- override fun getTasks(taskType: TaskType, userID: String?): Flow> =
- this.localRepository.getTasks(taskType, userID ?: this.userID)
+ override fun getTasks(taskType: TaskType, userID: String?, includedGroupIDs: Array): Flow> =
+ this.localRepository.getTasks(taskType, userID ?: this.userID, includedGroupIDs)
- override fun getTasksFlowable(taskType: TaskType, userID: String?): Flowable> =
- this.localRepository.getTasksFlowable(taskType, userID ?: this.userID)
+ override fun getTasksFlowable(taskType: TaskType, userID: String?, includedGroupIDs: Array): Flowable> =
+ this.localRepository.getTasksFlowable(taskType, userID ?: this.userID, includedGroupIDs)
override fun saveTasks(userId: String, order: TasksOrder, tasks: TaskList) {
localRepository.saveTasks(userId, order, tasks)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt
index 5099302cf..b8e1c1692 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt
@@ -2,17 +2,17 @@ package com.habitrpg.android.habitica.data.local
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.models.tasks.TaskList
+import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.common.habitica.models.tasks.TasksOrder
-import com.habitrpg.android.habitica.models.user.User
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import kotlinx.coroutines.flow.Flow
interface TaskLocalRepository : BaseLocalRepository {
- fun getTasks(taskType: TaskType, userID: String): Flow>
- fun getTasksFlowable(taskType: TaskType, userID: String): Flowable>
+ fun getTasks(taskType: TaskType, userID: String, includedGroupIDs: Array): Flow>
+ fun getTasksFlowable(taskType: TaskType, userID: String, includedGroupIDs: Array): Flowable>
fun getTasks(userId: String): Flow>
fun saveTasks(ownerID: String, tasksOrder: TasksOrder, tasks: TaskList)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt
index a97d3bb8e..0803d8525 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt
@@ -21,22 +21,30 @@ import kotlinx.coroutines.flow.filter
class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), TaskLocalRepository {
- override fun getTasks(taskType: TaskType, userID: String): Flow> {
+ override fun getTasks(taskType: TaskType, userID: String, includedGroupIDs: Array): Flow> {
if (realm.isClosed) return emptyFlow()
return realm.where(Task::class.java)
.equalTo("typeValue", taskType.value)
+ .beginGroup()
.equalTo("userId", userID)
+ .or()
+ .`in`("group.groupID", includedGroupIDs)
+ .endGroup()
.sort("position", Sort.ASCENDING, "dateCreated", Sort.DESCENDING)
.findAll()
.toFlow()
.filter { it.isLoaded }
}
- override fun getTasksFlowable(taskType: TaskType, userID: String): Flowable> {
+ override fun getTasksFlowable(taskType: TaskType, userID: String, includedGroupIDs: Array): Flowable> {
if (realm.isClosed) return Flowable.empty()
return RxJavaBridge.toV3Flowable(realm.where(Task::class.java)
.equalTo("typeValue", taskType.value)
+ .beginGroup()
.equalTo("userId", userID)
+ .or()
+ .`in`("group.groupID", includedGroupIDs)
+ .endGroup()
.sort("position", Sort.ASCENDING, "dateCreated", Sort.DESCENDING)
.findAll()
.asFlowable()
@@ -53,17 +61,20 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
}
override fun saveTasks(ownerID: String, tasksOrder: TasksOrder, tasks: TaskList) {
- val sortedTasks = ArrayList()
+ val sortedTasks = mutableListOf()
sortedTasks.addAll(sortTasks(tasks.tasks, tasksOrder.habits))
sortedTasks.addAll(sortTasks(tasks.tasks, tasksOrder.dailys))
sortedTasks.addAll(sortTasks(tasks.tasks, tasksOrder.todos))
sortedTasks.addAll(sortTasks(tasks.tasks, tasksOrder.rewards))
+ for (task in tasks.tasks.values) {
+ task.position = (sortedTasks.lastOrNull { it.type == task.type }?.position ?: -1) + 1
+ sortedTasks.add(task)
+ }
removeOldTasks(ownerID, sortedTasks)
val allChecklistItems = ArrayList()
val allReminders = ArrayList()
sortedTasks.forEach {
- if (it.userId.isBlank()) it.userId = ownerID
it.checklist?.let { it1 -> allChecklistItems.addAll(it1) }
it.reminders?.let { it1 -> allReminders.addAll(it1) }
}
@@ -110,11 +121,6 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
taskMap.remove(taskId)
}
}
- for (task in taskMap.values) {
- task.position = position
- taskList.add(task)
- position++
- }
return taskList
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt
index b812eb85f..6dfe805e3 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/TaskAlarmManager.kt
@@ -11,9 +11,9 @@ import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.models.tasks.RemindersItem
import com.habitrpg.android.habitica.models.tasks.Task
-import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.receivers.NotificationPublisher
import com.habitrpg.android.habitica.receivers.TaskReceiver
+import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.shared.habitica.HLogger
import com.habitrpg.shared.habitica.LogLevel
import kotlinx.coroutines.flow.firstOrNull
@@ -91,7 +91,7 @@ class TaskAlarmManager(
*/
private fun setAlarmForRemindersItem(reminderItemTask: Task, remindersItem: RemindersItem?) {
val now = ZonedDateTime.now().withZoneSameLocal(ZoneId.systemDefault())?.toInstant()
- if (remindersItem == null || (remindersItem.getLocalZonedDateTimeInstant()?.isBefore(now) == true && reminderItemTask.nextDue?.first() != null)) {
+ if (remindersItem == null || (remindersItem.getLocalZonedDateTimeInstant()?.isBefore(now) == true && reminderItemTask.nextDue?.firstOrNull() != null)) {
return
}
@@ -104,7 +104,7 @@ class TaskAlarmManager(
intent.putExtra(TASK_NAME_INTENT_KEY, reminderItemTask.text)
intent.putExtra(TASK_ID_INTENT_KEY, reminderItemTask.id)
- val intentId = remindersItem.id?.hashCode() ?: 0 and 0xfffffff
+ val intentId = remindersItem.id?.hashCode() ?: (0 and 0xfffffff)
// Cancel alarm if already exists
val previousSender = PendingIntent.getBroadcast(
context,
@@ -130,7 +130,7 @@ class TaskAlarmManager(
private fun removeAlarmForRemindersItem(remindersItem: RemindersItem) {
val intent = Intent(context, TaskReceiver::class.java)
intent.action = remindersItem.id
- val intentId = remindersItem.id?.hashCode() ?: 0 and 0xfffffff
+ val intentId = remindersItem.id?.hashCode() ?: (0 and 0xfffffff)
val sender = PendingIntent.getBroadcast(
context,
intentId,
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 49ac434a6..8ce4f6911 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
@@ -195,6 +195,10 @@ open class Task : RealmObject, BaseMainObject, Parcelable, BaseTask {
val isGroupTask: Boolean
get() = group?.groupID?.isNotBlank() == true
+ fun isAssignedToUser(userID: String): Boolean {
+ return group?.assignedUsers?.contains(userID) == true
+ }
+
val isPendingApproval: Boolean
get() = (group?.approvalRequired == true && group?.approvalRequested == true && group?.approvalApproved == false)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt
index 38df6c5d9..d8a35787c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/Preferences.kt
@@ -40,4 +40,5 @@ open class Preferences : RealmObject(), AvatarPreferences, BaseObject {
var pushNotifications: PushNotificationsPreference? = null
var emailNotifications: EmailNotificationsPreference? = null
var autoEquip: Boolean = true
+ var tasks: UserTaskPreferences? = null
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserTaskPreferences.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserTaskPreferences.kt
new file mode 100644
index 000000000..0be0ed8c0
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/UserTaskPreferences.kt
@@ -0,0 +1,13 @@
+package com.habitrpg.android.habitica.models.user
+
+import com.habitrpg.android.habitica.models.BaseObject
+import io.realm.RealmList
+import io.realm.RealmObject
+import io.realm.annotations.RealmClass
+
+@RealmClass(embedded = true)
+open class UserTaskPreferences: RealmObject(), BaseObject {
+ var confirmScoreNotes: Boolean = false
+ var mirrorGroupTasks: RealmList = RealmList()
+ var groupByChallenge: Boolean = false
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt
index 4de2a5f5f..8e87b3152 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/NotificationPublisher.kt
@@ -18,9 +18,9 @@ import com.habitrpg.android.habitica.extensions.withImmutableFlag
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.TaskAlarmManager
import com.habitrpg.android.habitica.models.tasks.Task
-import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.MainActivity
+import com.habitrpg.common.habitica.models.tasks.TaskType
import io.reactivex.rxjava3.functions.BiFunction
import java.util.Calendar
import java.util.Date
@@ -58,7 +58,7 @@ class NotificationPublisher : BroadcastReceiver() {
}
val checkDailies = intent.getBooleanExtra(CHECK_DAILIES, false)
if (checkDailies) {
- taskRepository.getTasksFlowable(TaskType.DAILY).firstElement().zipWith(
+ taskRepository.getTasksFlowable(TaskType.DAILY, null, emptyArray()).firstElement().zipWith(
userRepository.getUserFlowable().firstElement(),
BiFunction, User, Pair, User>> { tasks, user ->
return@BiFunction Pair(tasks, user)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
index 56a0080a2..04bd9ce07 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
@@ -65,7 +65,7 @@ class ArmoireActivity : BaseActivity() {
userViewModel.user.observeOnce(this) { user ->
gold = user?.stats?.gp
- val remaining = inventoryRepository.getArmoireRemainingCount() - 1
+ val remaining = inventoryRepository.getArmoireRemainingCount()
binding.equipmentCountView.text = getString(R.string.equipment_remaining, remaining)
binding.noEquipmentView.visibility = if (remaining > 0) View.GONE else View.VISIBLE
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt
index d2910c416..9278a6dcc 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/HabitButtonWidgetActivity.kt
@@ -13,10 +13,10 @@ import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.databinding.WidgetConfigureHabitButtonBinding
import com.habitrpg.android.habitica.helpers.RxErrorHandler
-import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter
import com.habitrpg.android.habitica.widget.HabitButtonWidgetProvider
+import com.habitrpg.common.habitica.models.tasks.TaskType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -82,7 +82,7 @@ class HabitButtonWidgetActivity : BaseActivity() {
binding.recyclerView.adapter = adapter
CoroutineScope(Dispatchers.Main + job).launch {
- adapter?.data = taskRepository.getTasks(TaskType.HABIT, userId).firstOrNull() ?: listOf()
+ adapter?.data = taskRepository.getTasks(TaskType.HABIT, userId, emptyArray()).firstOrNull() ?: listOf()
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt
index 6402d7999..f1a69cc4f 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseMainFragment.kt
@@ -17,11 +17,11 @@ import com.google.firebase.analytics.FirebaseAnalytics
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.data.UserRepository
-import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.android.habitica.extensions.setScaledPadding
import com.habitrpg.android.habitica.helpers.SoundManager
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper
+import com.habitrpg.common.habitica.extensions.getThemeColor
import javax.inject.Inject
abstract class BaseMainFragment : BaseFragment() {
@@ -96,7 +96,7 @@ abstract class BaseMainFragment : BaseFragment() {
open fun updateToolbarInteractivity() {
activity?.binding?.toolbarTitle?.background?.alpha = if (isTitleInteractive) 255 else 0
if (isTitleInteractive) {
- activity?.binding?.toolbarTitle?.setScaledPadding(context, 16, 1, 16, 1)
+ activity?.binding?.toolbarTitle?.setScaledPadding(context, 16, 4, 16, 4)
} else {
activity?.binding?.toolbarTitle?.setPadding(0)
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt
index d2b5a4f28..104af9689 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/skills/SkillTasksRecyclerViewFragment.kt
@@ -11,22 +11,21 @@ import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.databinding.FragmentRecyclerviewBinding
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.tasks.Task
-import com.habitrpg.common.habitica.models.tasks.TaskType
-import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.adapter.SkillTasksRecyclerViewAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
+import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
+import com.habitrpg.common.habitica.models.tasks.TaskType
import io.reactivex.rxjava3.core.BackpressureStrategy
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.subjects.PublishSubject
import kotlinx.coroutines.flow.map
import javax.inject.Inject
-import javax.inject.Named
class SkillTasksRecyclerViewFragment : BaseFragment() {
@Inject
lateinit var taskRepository: TaskRepository
- @field:[Inject Named(AppModule.NAMED_USER_ID)]
- lateinit var userId: String
+ @Inject
+ lateinit var userViewModel: MainUserViewModel
var taskType: TaskType? = null
override var binding: FragmentRecyclerviewBinding? = null
@@ -65,7 +64,8 @@ class SkillTasksRecyclerViewFragment : BaseFragment
)
binding?.recyclerView?.adapter = adapter
- var tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT)
+ val additionalGroupIDs = userViewModel.mirrorGroupTasks.toTypedArray()
+ var tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT, userViewModel.userID, additionalGroupIDs)
.map { it.filter { it.challengeID == null && it.group == null } }
if (taskType == TaskType.TODO) {
tasks = tasks.map { it.filter { !it.completed } }
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt
index eeee0b8e3..6752818ba 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt
@@ -329,8 +329,9 @@ open class TaskRecyclerViewFragment : BaseFragment(), SearchView.O
val taskTypeValue = args.taskType
if (args.ownerID?.isNotBlank() == true) {
viewModel.canSwitchOwners.value = false
- viewModel.ownerID.value = args.ownerID ?: viewModel.userID
+ viewModel.ownerID.value = args.ownerID ?: viewModel.userViewModel.userID
} else {
- viewModel.ownerID.value = viewModel.userID
+ viewModel.ownerID.value = viewModel.userViewModel.userID
}
if (taskTypeValue?.isNotBlank() == true) {
val taskType = TaskType.from(taskTypeValue)
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt
index 89a694e6b..3b29243c2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainUserViewModel.kt
@@ -7,16 +7,22 @@ import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.invitations.PartyInvite
import com.habitrpg.android.habitica.models.user.User
+import com.habitrpg.android.habitica.modules.AppModule
import io.reactivex.rxjava3.disposables.CompositeDisposable
+import javax.inject.Inject
+import javax.inject.Named
class MainUserViewModel(val userRepository: UserRepository) {
+ @field:[Inject Named(AppModule.NAMED_USER_ID)]
+ lateinit var injectedUserID: String
+
val formattedUsername: CharSequence?
get() = user.value?.formattedUsername
val partyInvitations: List
get() = user.value?.invitations?.parties ?: emptyList()
- val userID: String?
- get() = user.value?.id
+ val userID: String
+ get() = user.value?.id ?: injectedUserID
val username: CharSequence
get() = user.value?.username ?: ""
val displayName: CharSequence
@@ -27,6 +33,8 @@ class MainUserViewModel(val userRepository: UserRepository) {
get() = (user.value?.stats?.hp ?: 1.0) == 0.0
val isUserInParty: Boolean
get() = user.value?.hasParty == true
+ val mirrorGroupTasks: List
+ get() = user.value?.preferences?.tasks?.mirrorGroupTasks ?: emptyList()
val user: LiveData
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt
index a4f3a62c9..fd16b33ca 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/TasksViewModel.kt
@@ -11,11 +11,10 @@ import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.helpers.AmplitudeManager
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
+import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.common.habitica.models.responses.TaskDirection
import com.habitrpg.common.habitica.models.responses.TaskScoringResult
-import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.common.habitica.models.tasks.TaskType
-import com.habitrpg.android.habitica.modules.AppModule
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.realm.Case
import io.realm.OrderedRealmCollection
@@ -24,7 +23,6 @@ import io.realm.Sort
import kotlinx.coroutines.launch
import java.util.Date
import javax.inject.Inject
-import javax.inject.Named
class TasksViewModel : BaseViewModel() {
private var compositeSubscription: CompositeDisposable = CompositeDisposable()
@@ -33,8 +31,6 @@ class TasksViewModel : BaseViewModel() {
component.inject(this)
}
- @field:[Inject Named(AppModule.NAMED_USER_ID)]
- lateinit var userID: String
@Inject
lateinit var taskRepository: TaskRepository
@Inject
@@ -53,7 +49,7 @@ class TasksViewModel : BaseViewModel() {
val isPersonalBoard: Boolean
get() {
- return ownerID.value == userID
+ return ownerID.value == userViewModel.userID
}
val ownerTitle: CharSequence
get() {
@@ -65,7 +61,7 @@ class TasksViewModel : BaseViewModel() {
viewModelScope.launch {
userRepository.getTeamPlans()
.collect {
- owners = listOf(Pair(userID, userViewModel.displayName)) + it.map {
+ owners = listOf(Pair(userViewModel.userID, userViewModel.displayName)) + it.map {
Pair(
it.id,
it.summary
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt
index 132d5c68e..cc6047130 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/yesterdailies/YesterdailyDialog.kt
@@ -12,14 +12,14 @@ import androidx.core.content.ContextCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.UserRepository
-import com.habitrpg.common.habitica.extensions.dpToPx
-import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
import com.habitrpg.android.habitica.helpers.AmplitudeManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.tasks.ChecklistItem
import com.habitrpg.android.habitica.models.tasks.Task
-import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
+import com.habitrpg.common.habitica.extensions.dpToPx
+import com.habitrpg.common.habitica.extensions.isUsingNightModeResources
+import com.habitrpg.common.habitica.models.tasks.TaskType
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import java.lang.ref.WeakReference
@@ -226,7 +226,7 @@ class YesterdailyDialog private constructor(
}
.firstElement()
.zipWith(
- taskRepository.getTasksFlowable(TaskType.DAILY).firstElement()
+ taskRepository.getTasksFlowable(TaskType.DAILY, null, emptyArray()).firstElement()
.map {
val taskMap = mutableMapOf()
it.forEachIndexed { index, task -> taskMap[task.id ?: ""] = index }
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt
index b4845d870..bea720fa2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/utils/TaskSerializer.kt
@@ -5,6 +5,7 @@ import com.google.gson.JsonDeserializationContext
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonObject
+import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializationContext
import com.google.gson.JsonSerializer
import com.habitrpg.android.habitica.extensions.getAsString
@@ -20,6 +21,13 @@ import io.realm.RealmList
import java.lang.reflect.Type
import java.util.Date
+private val JsonPrimitive.asBooleanOrFalse: Boolean
+ get() = if (isBoolean) {
+ asBoolean
+ } else {
+ false
+ }
+
class TaskSerializer : JsonSerializer, JsonDeserializer {
private fun getIntListFromJsonArray(jsonArray: JsonArray): List {
@@ -116,11 +124,11 @@ class TaskSerializer : JsonSerializer, JsonDeserializer {
if (obj.has("group")) {
val groupObject = obj.getAsJsonObject("group")
val group: TaskGroupPlan = context.deserialize(groupObject, TaskGroupPlan::class.java)
- if (group.groupID?.isNotBlank() == true) {
+ if (group.groupID?.isNotBlank() == true && groupObject.has("approval")) {
val approvalObject = groupObject.getAsJsonObject("approval")
- if (approvalObject.has("requested")) group.approvalRequested = approvalObject.getAsJsonPrimitive("requested").asBoolean
- if (approvalObject.has("approved")) group.approvalApproved = approvalObject.getAsJsonPrimitive("approved").asBoolean
- if (approvalObject.has("required")) group.approvalRequired = approvalObject.getAsJsonPrimitive("required").asBoolean
+ if (approvalObject.has("requested")) group.approvalRequested = approvalObject.getAsJsonPrimitive("requested").asBooleanOrFalse
+ if (approvalObject.has("approved")) group.approvalApproved = approvalObject.getAsJsonPrimitive("approved").asBooleanOrFalse
+ if (approvalObject.has("required")) group.approvalRequired = approvalObject.getAsJsonPrimitive("required").asBooleanOrFalse
task.group = group
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
index 1cc60c14d..7e7118698 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/AvatarStatsWidgetProvider.kt
@@ -5,29 +5,32 @@ import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.os.Build
import android.view.View
import android.view.ViewGroup
import android.widget.RemoteViews
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
-import com.habitrpg.common.habitica.extensions.dpToPx
import com.habitrpg.android.habitica.extensions.withImmutableFlag
-import com.habitrpg.common.habitica.helpers.HealthFormatter
-import com.habitrpg.common.habitica.helpers.NumberAbbreviator
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.user.User
-import com.habitrpg.common.habitica.views.AvatarView
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
+import com.habitrpg.common.habitica.extensions.dpToPx
+import com.habitrpg.common.habitica.helpers.HealthFormatter
+import com.habitrpg.common.habitica.helpers.NumberAbbreviator
+import com.habitrpg.common.habitica.views.AvatarView
class AvatarStatsWidgetProvider : BaseWidgetProvider() {
+ private lateinit var avatarView: AvatarView
private var user: User? = null
private var appWidgetManager: AppWidgetManager? = null
private var showManaBar: Boolean = true
private var showAvatar: Boolean = true
+
override fun layoutResourceId(): Int {
return R.layout.widget_avatar_stats
}
@@ -41,6 +44,10 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
override fun onEnabled(context: Context) {
super.onEnabled(context)
+ avatarView = AvatarView(context, showBackground = true, showMount = true, showPet = true)
+ val layoutParams = ViewGroup.LayoutParams(140.dpToPx(context), 147.dpToPx(context))
+ avatarView.layoutParams = layoutParams
+
this.setUp()
userRepository.getUserFlowable().subscribe({
user = it
@@ -54,6 +61,11 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
appWidgetIds: IntArray
) {
super.onUpdate(context, appWidgetManager, appWidgetIds)
+ if (!this::avatarView.isInitialized) {
+ avatarView = AvatarView(context, showBackground = true, showMount = true, showPet = true)
+ val layoutParams = ViewGroup.LayoutParams(140.dpToPx(context), 147.dpToPx(context))
+ avatarView.layoutParams = layoutParams
+ }
this.setUp()
this.appWidgetManager = appWidgetManager
this.context = context
@@ -74,7 +86,7 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
columns: Int,
rows: Int
): RemoteViews {
- showAvatar = columns > 3
+ showAvatar = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) columns > 4 else columns > 3
if (showAvatar) {
remoteViews.setViewVisibility(R.id.avatar_view, View.VISIBLE)
} else {
@@ -141,10 +153,6 @@ class AvatarStatsWidgetProvider : BaseWidgetProvider() {
remoteViews.setTextViewText(R.id.lvl_tv, context.getString(R.string.user_level, user.stats?.lvl ?: 0))
if (showAvatar) {
- val avatarView =
- AvatarView(context, showBackground = true, showMount = true, showPet = true)
- val layoutParams = ViewGroup.LayoutParams(140.dpToPx(context), 147.dpToPx(context))
- avatarView.layoutParams = layoutParams
avatarView.setAvatar(user)
val finalRemoteViews = remoteViews
avatarView.onAvatarImageReady { bitmap ->
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.kt
index 5fb927d14..026d925e8 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListFactory.kt
@@ -11,8 +11,8 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.UserRepository
import com.habitrpg.android.habitica.models.tasks.Task
-import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.common.habitica.helpers.MarkdownParser
+import com.habitrpg.common.habitica.models.tasks.TaskType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
@@ -46,7 +46,7 @@ abstract class TaskListFactory internal constructor(
return
}
CoroutineScope(Dispatchers.Main + job).launch {
- val tasks = taskRepository.getTasks(taskType).firstOrNull()?.filter { task ->
+ val tasks = taskRepository.getTasks(taskType, null, emptyArray()).firstOrNull()?.filter { task ->
task.type == TaskType.TODO && !task.completed || task.isDisplayedActive
} ?: return@launch
taskList = taskRepository.getTaskCopies(tasks)
diff --git a/version.properties b/version.properties
index 9118e3a28..2bdfb8477 100644
--- a/version.properties
+++ b/version.properties
@@ -1,2 +1,2 @@
NAME=4.0.1
-CODE=4360
\ No newline at end of file
+CODE=4370
\ No newline at end of file