Improve group task display

This commit is contained in:
Phillip Thelen 2022-08-16 10:56:04 +02:00
parent 149e5b01a7
commit a7e3e11526
23 changed files with 119 additions and 75 deletions

View file

@ -265,10 +265,9 @@
<string name="notification_purchase_reward" >You purchased a reward</string>
<string name="world_quest">World Quest</string>
<string name="inn_description">Need a break? Check into Daniels Inn to pause some of Habiticas more difficult game mechanics:\n\n
&#8226; Missed Dailies wont damage you\n
&#8226; Tasks wont lose streaks or decay in color\n
&#8226; Bosses wont do damage for your missed Dailies\n
&#8226; Your boss damage or collection quest items will stay pending until check-out</string>
&#8226; Your missed Dailies won\'t damage you (bosses will still do damage caused by other Party member\'s missed Dailies)
&#8226; Your Task streaks and Habit counters will not reset
&#8226; Your damage to the Quest boss or found collection items will remain pending until you check out of the Inn</string>
<string name="empty_items">You don\'t have any %s</string>
<string name="user_level_with_class">Lvl %1$d %2$s</string>
<string name="user_level_with_class_unabbreviated">Level %1$d %2$s</string>

View file

@ -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<List<Task>>
fun getTasksFlowable(taskType: TaskType, userID: String? = null): Flowable<out List<Task>>
fun getTasks(taskType: TaskType, userID: String? = null, includedGroupIDs: Array<String>): Flow<List<Task>>
fun getTasksFlowable(taskType: TaskType, userID: String? = null, includedGroupIDs: Array<String>): Flowable<out List<Task>>
fun saveTasks(userId: String, order: TasksOrder, tasks: TaskList)
fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable<TaskList>

View file

@ -39,11 +39,11 @@ class TaskRepositoryImpl(
) : BaseRepositoryImpl<TaskLocalRepository>(localRepository, apiClient, userID), TaskRepository {
private var lastTaskAction: Long = 0
override fun getTasks(taskType: TaskType, userID: String?): Flow<List<Task>> =
this.localRepository.getTasks(taskType, userID ?: this.userID)
override fun getTasks(taskType: TaskType, userID: String?, includedGroupIDs: Array<String>): Flow<List<Task>> =
this.localRepository.getTasks(taskType, userID ?: this.userID, includedGroupIDs)
override fun getTasksFlowable(taskType: TaskType, userID: String?): Flowable<out List<Task>> =
this.localRepository.getTasksFlowable(taskType, userID ?: this.userID)
override fun getTasksFlowable(taskType: TaskType, userID: String?, includedGroupIDs: Array<String>): Flowable<out List<Task>> =
this.localRepository.getTasksFlowable(taskType, userID ?: this.userID, includedGroupIDs)
override fun saveTasks(userId: String, order: TasksOrder, tasks: TaskList) {
localRepository.saveTasks(userId, order, tasks)

View file

@ -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<List<Task>>
fun getTasksFlowable(taskType: TaskType, userID: String): Flowable<out List<Task>>
fun getTasks(taskType: TaskType, userID: String, includedGroupIDs: Array<String>): Flow<List<Task>>
fun getTasksFlowable(taskType: TaskType, userID: String, includedGroupIDs: Array<String>): Flowable<out List<Task>>
fun getTasks(userId: String): Flow<List<Task>>
fun saveTasks(ownerID: String, tasksOrder: TasksOrder, tasks: TaskList)

View file

@ -21,22 +21,30 @@ import kotlinx.coroutines.flow.filter
class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), TaskLocalRepository {
override fun getTasks(taskType: TaskType, userID: String): Flow<List<Task>> {
override fun getTasks(taskType: TaskType, userID: String, includedGroupIDs: Array<String>): Flow<List<Task>> {
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<out List<Task>> {
override fun getTasksFlowable(taskType: TaskType, userID: String, includedGroupIDs: Array<String>): Flowable<out List<Task>> {
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<Task>()
val sortedTasks = mutableListOf<Task>()
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<ChecklistItem>()
val allReminders = ArrayList<RemindersItem>()
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
}

View file

@ -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,

View file

@ -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)

View file

@ -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
}

View file

@ -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<String> = RealmList()
var groupByChallenge: Boolean = false
}

View file

@ -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<List<Task>, User, Pair<List<Task>, User>> { tasks, user ->
return@BiFunction Pair(tasks, user)

View file

@ -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
}

View file

@ -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()
}
}

View file

@ -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<VB : ViewBinding> : BaseFragment<VB>() {
@ -96,7 +96,7 @@ abstract class BaseMainFragment<VB : ViewBinding> : BaseFragment<VB>() {
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)
}

View file

@ -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<FragmentRecyclerviewBinding>() {
@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<FragmentRecyclerviewBinding>
)
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 } }

View file

@ -329,8 +329,9 @@ open class TaskRecyclerViewFragment : BaseFragment<FragmentRefreshRecyclerviewBi
if (taskFlowJob?.isActive == true) {
taskFlowJob?.cancel()
}
val additionalGroupIDs = viewModel.userViewModel.mirrorGroupTasks.toTypedArray()
taskFlowJob = lifecycleScope.launch {
taskRepository.getTasks(taskType, ownerID).collect {
taskRepository.getTasks(taskType, ownerID, additionalGroupIDs).collect {
recyclerAdapter?.updateUnfilteredData(it)
}
}

View file

@ -24,17 +24,17 @@ import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.databinding.FragmentViewpagerBinding
import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.android.habitica.extensions.setTintWith
import com.habitrpg.android.habitica.helpers.AmplitudeManager
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.common.habitica.models.tasks.TaskType
import com.habitrpg.android.habitica.ui.activities.TaskFormActivity
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.viewmodels.TasksViewModel
import com.habitrpg.android.habitica.ui.views.navigation.HabiticaBottomNavigationViewListener
import com.habitrpg.android.habitica.ui.views.tasks.TaskFilterDialog
import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.common.habitica.models.tasks.TaskType
import java.util.Date
import java.util.WeakHashMap
@ -80,9 +80,9 @@ class TasksFragment : BaseMainFragment<FragmentViewpagerBinding>(), 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)

View file

@ -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<PartyInvite>
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<String>
get() = user.value?.preferences?.tasks?.mirrorGroupTasks ?: emptyList()
val user: LiveData<User?>

View file

@ -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

View file

@ -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<String, Int>()
it.forEachIndexed { index, task -> taskMap[task.id ?: ""] = index }

View file

@ -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<Task>, JsonDeserializer<Task> {
private fun getIntListFromJsonArray(jsonArray: JsonArray): List<Int> {
@ -116,11 +124,11 @@ class TaskSerializer : JsonSerializer<Task>, JsonDeserializer<Task> {
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
}
}

View file

@ -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 ->

View file

@ -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)

View file

@ -1,2 +1,2 @@
NAME=4.0.1
CODE=4360
CODE=4370