Continue group plan work
BIN
Habitica/res/drawable-hdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1,012 B |
BIN
Habitica/res/drawable-mdpi/assign.png
Normal file
|
After Width: | Height: | Size: 691 B |
BIN
Habitica/res/drawable-night-hdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
Habitica/res/drawable-night-mdpi/assign.png
Normal file
|
After Width: | Height: | Size: 695 B |
BIN
Habitica/res/drawable-night-xhdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Habitica/res/drawable-night-xxhdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
Habitica/res/drawable-xhdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Habitica/res/drawable-xxhdpi/assign.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
|
|
@ -49,7 +49,7 @@
|
|||
android:paddingBottom="2dp"/>
|
||||
<TextView
|
||||
android:id="@+id/priceLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/yellow_10"
|
||||
android:gravity="center_horizontal"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@
|
|||
style="@style/Caption4"
|
||||
android:text="@string/pending_approval"
|
||||
android:textColor="@color/text_ternary"
|
||||
android:drawableStart="@drawable/assign"
|
||||
android:drawablePadding="@dimen/spacing_small"
|
||||
android:layout_marginBottom="2dp"
|
||||
/>
|
||||
<com.habitrpg.android.habitica.ui.views.EllipsisTextView
|
||||
android:id="@+id/checkedTextView"
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
<dimen name="checkbox_size">24dp</dimen>
|
||||
<dimen name="checkbox_compact_size">20dp</dimen>
|
||||
|
||||
<dimen name="task_top_bottom_padding">10dp</dimen>
|
||||
<dimen name="task_top_bottom_padding">8dp</dimen>
|
||||
<dimen name="task_top_bottom_compact_padding">8dp</dimen>
|
||||
<dimen name="reward_spacing">8dp</dimen>
|
||||
<dimen name="grid_item_margin">6dp</dimen>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,15 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
.beginGroup()
|
||||
.equalTo("userId", ownerID)
|
||||
.or()
|
||||
.beginGroup()
|
||||
.`in`("group.groupID", includedGroupIDs)
|
||||
.and()
|
||||
.beginGroup()
|
||||
.contains("group.assignedUsers", ownerID)
|
||||
.or()
|
||||
.isEmpty("group.assignedUsers")
|
||||
.endGroup()
|
||||
.endGroup()
|
||||
.or()
|
||||
.equalTo("group.groupID", ownerID)
|
||||
.endGroup()
|
||||
|
|
@ -129,14 +137,13 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm),
|
|||
return taskList
|
||||
}
|
||||
|
||||
private fun removeOldTasks(userID: String, onlineTaskList: List<Task>) {
|
||||
val groupIDs = onlineTaskList.map { it.group?.groupID }.distinct().toTypedArray()
|
||||
private fun removeOldTasks(ownerID: String, onlineTaskList: List<Task>) {
|
||||
if (realm.isClosed) return
|
||||
val localTasks = realm.where(Task::class.java)
|
||||
.beginGroup()
|
||||
.equalTo("userId", userID)
|
||||
.equalTo("userId", ownerID)
|
||||
.or()
|
||||
.`in`("group.groupID", groupIDs)
|
||||
.equalTo("group.groupID", ownerID)
|
||||
.endGroup()
|
||||
.beginGroup()
|
||||
.beginGroup()
|
||||
|
|
|
|||
|
|
@ -1,7 +0,0 @@
|
|||
package com.habitrpg.android.habitica.helpers
|
||||
|
||||
import android.content.res.Resources
|
||||
|
||||
interface AssignedTextProvider {
|
||||
fun textForTask(resources: Resources, assignedUsers: List<String>): String
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.habitrpg.android.habitica.helpers
|
||||
|
||||
import android.content.res.Resources
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
|
||||
interface GroupPlanInfoProvider {
|
||||
fun assignedTextForTask(resources: Resources, assignedUsers: List<String>): String
|
||||
fun canScoreTask(task: Task): Boolean
|
||||
fun canEditTask(task: Task): Boolean
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ class RewardsRecyclerViewAdapter(
|
|||
if (customRewards != null && position < customRewardCount) {
|
||||
val reward = customRewards?.get(position) ?: return
|
||||
val gold = user?.stats?.gp ?: 0.0
|
||||
(holder as? RewardViewHolder)?.isLocked = false
|
||||
(holder as? RewardViewHolder)?.isLocked = !viewModel.canScoreTask(reward)
|
||||
(holder as? RewardViewHolder)?.bind(reward, position, reward.value <= gold, taskDisplayMode, viewModel.ownerID.value)
|
||||
} else if (inAppRewards != null) {
|
||||
val item = inAppRewards?.get(position - customRewardCount) ?: return
|
||||
|
|
@ -122,7 +122,9 @@ class RewardsRecyclerViewAdapter(
|
|||
|
||||
override fun getItemCount(): Int {
|
||||
var rewardCount = customRewardCount
|
||||
rewardCount += inAppRewardCount
|
||||
if (viewModel.isPersonalBoard) {
|
||||
rewardCount += inAppRewardCount
|
||||
}
|
||||
return rewardCount
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,15 +16,14 @@ import com.habitrpg.android.habitica.R
|
|||
import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.shared.habitica.models.tasks.TaskType
|
||||
import com.habitrpg.android.habitica.ui.activities.MainActivity
|
||||
import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter
|
||||
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
|
||||
import com.habitrpg.shared.habitica.models.tasks.TaskType
|
||||
import io.reactivex.rxjava3.functions.Consumer
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.*
|
||||
|
||||
class RewardsRecyclerviewFragment : TaskRecyclerViewFragment() {
|
||||
|
||||
|
|
@ -45,7 +44,7 @@ class RewardsRecyclerviewFragment : TaskRecyclerViewFragment() {
|
|||
|
||||
(layoutManager as? GridLayoutManager)?.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (recyclerAdapter?.getItemViewType(position) ?: 0 < 2) {
|
||||
return if ((recyclerAdapter?.getItemViewType(position) ?: 0) < 2) {
|
||||
(layoutManager as? GridLayoutManager)?.spanCount ?: 1
|
||||
} else {
|
||||
1
|
||||
|
|
|
|||
|
|
@ -214,7 +214,6 @@ open class TaskRecyclerViewFragment : BaseFragment<FragmentRefreshRecyclerviewBi
|
|||
component.inject(this)
|
||||
}
|
||||
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
savedInstanceState?.let { this.taskType = TaskType.from(savedInstanceState.getString(CLASS_TYPE_KEY, "")) ?: TaskType.HABIT }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import android.widget.ProgressBar
|
|||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.BindableViewHolder
|
||||
|
|
@ -36,7 +36,7 @@ abstract class BaseTaskViewHolder constructor(
|
|||
var scoreTaskFunc: ((Task, TaskDirection) -> Unit),
|
||||
var openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
var brokenTaskFunc: ((Task) -> Unit),
|
||||
var assignedTextProvider: AssignedTextProvider?
|
||||
var assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : BindableViewHolder<Task>(itemView), View.OnTouchListener {
|
||||
private val scope = MainScope()
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ abstract class BaseTaskViewHolder constructor(
|
|||
}
|
||||
|
||||
if (data.group?.assignedUsers?.isNotEmpty() == true) {
|
||||
assignedTextView.text = assignedTextProvider?.textForTask(context.resources, data.group?.assignedUsers ?: emptyList())
|
||||
assignedTextView.text = assignedTextProvider?.assignedTextForTask(context.resources, data.group?.assignedUsers ?: emptyList())
|
||||
assignedTextView.visibility = View.VISIBLE
|
||||
} else {
|
||||
assignedTextView.visibility = View.GONE
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.models.tasks.ChecklistItem
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
|
|
@ -32,7 +32,7 @@ abstract class ChecklistedViewHolder(
|
|||
var scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit),
|
||||
openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
brokenTaskFunc: ((Task) -> Unit),
|
||||
assignedTextProvider: AssignedTextProvider?
|
||||
assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc, assignedTextProvider) {
|
||||
|
||||
private val checkboxHolder: ViewGroup = itemView.findViewById(R.id.checkBoxHolder)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.habitrpg.android.habitica.ui.viewHolders.tasks
|
||||
|
||||
import android.view.View
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
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
|
||||
|
|
@ -15,7 +15,7 @@ class DailyViewHolder(
|
|||
scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit),
|
||||
openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
brokenTaskFunc: ((Task) -> Unit),
|
||||
assignedTextProvider: AssignedTextProvider?
|
||||
assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc, brokenTaskFunc, assignedTextProvider) {
|
||||
|
||||
override val taskIconWrapperIsVisible: Boolean
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ import android.widget.Button
|
|||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskDirection
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ class HabitViewHolder(
|
|||
scoreTaskFunc: ((Task, TaskDirection) -> Unit),
|
||||
openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
brokenTaskFunc: ((Task) -> Unit),
|
||||
assignedTextProvider: AssignedTextProvider?
|
||||
assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc, assignedTextProvider) {
|
||||
|
||||
private val btnPlusWrapper: FrameLayout = itemView.findViewById(R.id.btnPlusWrapper)
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ import android.view.MotionEvent
|
|||
import android.view.View
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.RewardItemCardBinding
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.ui.ItemDetailDialog
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.common.habitica.extensions.dpToPx
|
||||
import com.habitrpg.common.habitica.helpers.NumberAbbreviator
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskDirection
|
||||
|
||||
|
|
@ -18,8 +20,14 @@ class RewardViewHolder(
|
|||
scoreTaskFunc: ((Task, TaskDirection) -> Unit),
|
||||
openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
brokenTaskFunc: ((Task) -> Unit),
|
||||
assignedTextProvider: AssignedTextProvider?
|
||||
) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc, assignedTextProvider) {
|
||||
assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : BaseTaskViewHolder(
|
||||
itemView,
|
||||
scoreTaskFunc,
|
||||
openTaskFunc,
|
||||
brokenTaskFunc,
|
||||
assignedTextProvider
|
||||
) {
|
||||
private val binding = RewardItemCardBinding.bind(itemView)
|
||||
|
||||
private val isItem: Boolean
|
||||
|
|
@ -29,6 +37,7 @@ class RewardViewHolder(
|
|||
binding.buyButton.setOnClickListener {
|
||||
buyReward()
|
||||
}
|
||||
binding.goldIcon.setImageBitmap(HabiticaIconsHelper.imageOfGold())
|
||||
}
|
||||
|
||||
override fun canContainMarkdown(): Boolean {
|
||||
|
|
@ -67,25 +76,44 @@ class RewardViewHolder(
|
|||
this.task = reward
|
||||
streakTextView.visibility = View.GONE
|
||||
super.bind(reward, position, displayMode, ownerID)
|
||||
binding.priceLabel.text = NumberAbbreviator.abbreviate(itemView.context, this.task?.value ?: 0.0)
|
||||
binding.priceLabel.text =
|
||||
NumberAbbreviator.abbreviate(itemView.context, this.task?.value ?: 0.0)
|
||||
|
||||
if (isLocked) {
|
||||
binding.goldIcon.setImageResource(R.drawable.task_lock)
|
||||
binding.goldIcon.drawable.setTint(ContextCompat.getColor(context, R.color.reward_buy_button_text))
|
||||
binding.goldIcon.alpha = 1.0f
|
||||
binding.priceLabel.setTextColor(ContextCompat.getColor(context, R.color.reward_buy_button_text))
|
||||
binding.buyButton.setBackgroundColor(ContextCompat.getColor(context, R.color.reward_buy_button_bg))
|
||||
binding.priceLabel.setCompoundDrawablesWithIntrinsicBounds(
|
||||
HabiticaIconsHelper.imageOfLocked(
|
||||
ContextCompat.getColor(context, R.color.gray_1_30), 10, 12
|
||||
).toDrawable(context.resources), null, null, null
|
||||
)
|
||||
binding.priceLabel.compoundDrawablePadding = 2.dpToPx(context)
|
||||
} else {
|
||||
binding.goldIcon.setImageBitmap(HabiticaIconsHelper.imageOfGold())
|
||||
if (canBuy) {
|
||||
binding.goldIcon.alpha = 1.0f
|
||||
binding.priceLabel.setTextColor(ContextCompat.getColor(context, R.color.reward_buy_button_text))
|
||||
binding.buyButton.setBackgroundColor(ContextCompat.getColor(context, R.color.reward_buy_button_bg))
|
||||
} else {
|
||||
binding.goldIcon.alpha = 0.6f
|
||||
binding.priceLabel.setTextColor(ContextCompat.getColor(context, R.color.text_quad))
|
||||
binding.buyButton.setBackgroundColor(ColorUtils.setAlphaComponent(ContextCompat.getColor(context, R.color.offset_background), 127))
|
||||
}
|
||||
binding.priceLabel.setCompoundDrawables(null, null, null, null)
|
||||
}
|
||||
if (canBuy && !isLocked) {
|
||||
binding.goldIcon.alpha = 1.0f
|
||||
binding.priceLabel.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.reward_buy_button_text
|
||||
)
|
||||
)
|
||||
binding.buyButton.setBackgroundColor(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.reward_buy_button_bg
|
||||
)
|
||||
)
|
||||
} else {
|
||||
binding.goldIcon.alpha = 0.6f
|
||||
binding.priceLabel.setTextColor(ContextCompat.getColor(context, R.color.text_quad))
|
||||
binding.buyButton.setBackgroundColor(
|
||||
ColorUtils.setAlphaComponent(
|
||||
ContextCompat.getColor(
|
||||
context,
|
||||
R.color.offset_background
|
||||
), 127
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.habitrpg.android.habitica.ui.viewHolders.tasks
|
||||
|
||||
import android.view.View
|
||||
import com.habitrpg.android.habitica.helpers.AssignedTextProvider
|
||||
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
|
||||
|
|
@ -13,7 +13,7 @@ class TodoViewHolder(
|
|||
scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit),
|
||||
openTaskFunc: ((Pair<Task, View>) -> Unit),
|
||||
brokenTaskFunc: ((Task) -> Unit),
|
||||
assignedTextProvider: AssignedTextProvider?
|
||||
assignedTextProvider: GroupPlanInfoProvider?
|
||||
) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc, brokenTaskFunc, assignedTextProvider) {
|
||||
|
||||
private val dateFormatter: DateFormat = android.text.format.DateFormat.getDateFormat(context)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import com.habitrpg.android.habitica.data.UserRepository
|
|||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.models.TeamPlan
|
||||
import com.habitrpg.android.habitica.models.invitations.PartyInvite
|
||||
import com.habitrpg.android.habitica.models.members.Member
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
|
|
@ -43,10 +44,12 @@ class MainUserViewModel(private val providedUserID: String, val userRepository:
|
|||
.filterNotNull()
|
||||
.distinctUntilChanged { old, new -> old.id == new.id }
|
||||
.flatMapLatest { socialRepository.getGroup(it.id) }
|
||||
var currentTeamPlanMembers = currentTeamPlan
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
var currentTeamPlanMembers: LiveData<List<Member>> = currentTeamPlan
|
||||
.filterNotNull()
|
||||
.distinctUntilChanged { old, new -> old.id == new.id }
|
||||
.flatMapLatest { socialRepository.getGroupMembers(it.id) }
|
||||
.asLiveData()
|
||||
|
||||
fun onCleared() {
|
||||
userRepository.close()
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ import com.habitrpg.android.habitica.data.TagRepository
|
|||
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.AssignedTextProvider
|
||||
import com.habitrpg.android.habitica.helpers.ExceptionHandler
|
||||
import com.habitrpg.android.habitica.helpers.GroupPlanInfoProvider
|
||||
import com.habitrpg.android.habitica.models.TeamPlan
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.shared.habitica.models.responses.TaskDirection
|
||||
|
|
@ -28,7 +28,7 @@ import kotlinx.coroutines.launch
|
|||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
|
||||
class TasksViewModel : BaseViewModel(), AssignedTextProvider {
|
||||
class TasksViewModel : BaseViewModel(), GroupPlanInfoProvider {
|
||||
private var compositeSubscription: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun inject(component: UserComponent) {
|
||||
|
|
@ -305,14 +305,21 @@ class TasksViewModel : BaseViewModel(), AssignedTextProvider {
|
|||
return query
|
||||
}
|
||||
|
||||
fun canScoreTask(item: Task): Boolean {
|
||||
if (!item.isGroupTask) {
|
||||
override fun canScoreTask(task: Task): Boolean {
|
||||
if (!task.isGroupTask) {
|
||||
return true
|
||||
}
|
||||
return item.isAssignedToUser(userViewModel.userID) || item.group?.assignedUsers?.isEmpty() != false
|
||||
return task.isAssignedToUser(userViewModel.userID) || task.group?.assignedUsers?.isEmpty() != false
|
||||
}
|
||||
|
||||
override fun textForTask(resources: Resources, assignedUsers: List<String>): String {
|
||||
override fun canEditTask(task: Task): Boolean {
|
||||
if (!task.isGroupTask) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun assignedTextForTask(resources: Resources, assignedUsers: List<String>): String {
|
||||
return if (assignedUsers.contains(userViewModel.userID)) {
|
||||
if (assignedUsers.size == 1) {
|
||||
resources.getString(R.string.you)
|
||||
|
|
@ -320,7 +327,11 @@ class TasksViewModel : BaseViewModel(), AssignedTextProvider {
|
|||
resources.getQuantityString(R.plurals.you_x_others, assignedUsers.size - 1, assignedUsers.size - 1)
|
||||
}
|
||||
} else {
|
||||
resources.getQuantityString(R.plurals.people, assignedUsers.size, assignedUsers.size)
|
||||
if (assignedUsers.size == 1) {
|
||||
userViewModel.currentTeamPlanMembers.value?.firstOrNull { it.id == assignedUsers.first() }?.displayName ?: ""
|
||||
} else {
|
||||
resources.getQuantityString(R.plurals.people, assignedUsers.size, assignedUsers.size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ fun AppHeaderView(
|
|||
) {
|
||||
val user by viewModel.user.observeAsState(null)
|
||||
val teamPlan by viewModel.currentTeamPlan.collectAsState(null)
|
||||
val teamPlanMembers by viewModel.currentTeamPlanMembers.collectAsState(null)
|
||||
val teamPlanMembers by viewModel.currentTeamPlanMembers.observeAsState()
|
||||
Column {
|
||||
Row {
|
||||
ComposableAvatarView(
|
||||
|
|
@ -207,7 +207,10 @@ fun AppHeaderView(
|
|||
}
|
||||
) {
|
||||
for (member in teamPlanMembers?.filter { it.id != user?.id }?.take(6) ?: emptyList()) {
|
||||
Box(modifier = Modifier.clip(CircleShape).size(26.dp).padding(end = 6.dp, top = 4.dp)) {
|
||||
Box(modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(26.dp)
|
||||
.padding(end = 6.dp, top = 4.dp)) {
|
||||
ComposableAvatarView(
|
||||
avatar = member,
|
||||
Modifier
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import android.content.Context
|
|||
import android.graphics.PorterDuff
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.BounceInterpolator
|
||||
import android.view.animation.LinearInterpolator
|
||||
|
|
@ -68,28 +67,11 @@ class HabiticaBottomNavigationView @JvmOverloads constructor(
|
|||
field = value
|
||||
val animator = ObjectAnimator.ofFloat(0f, 1.0f)
|
||||
if (field) {
|
||||
val params = binding.cutoutFill.layoutParams
|
||||
// add some additional height because otherwise there is a weird white line
|
||||
params.height = binding.cutoutBackground.height + 10
|
||||
binding.cutoutFill.layoutParams = params
|
||||
animator.addUpdateListener {
|
||||
val reversed = 1.0f - it.animatedFraction
|
||||
binding.cutoutFill.translationY = -(reversed) * binding.cutoutBackground.height
|
||||
}
|
||||
binding.cutoutSpace.visibility = View.VISIBLE
|
||||
binding.addButtonBackground.animate()
|
||||
.translationY(0f)
|
||||
.alpha(1f)
|
||||
.setDuration(200)
|
||||
} else {
|
||||
val params = binding.cutoutFill.layoutParams
|
||||
// add some additional height because otherwise there is a weird white line
|
||||
params.height = binding.cutoutBackground.height + 10
|
||||
binding.cutoutFill.layoutParams = params
|
||||
animator.addUpdateListener {
|
||||
binding.cutoutFill.translationY = -it.animatedFraction * (binding.cutoutBackground.height)
|
||||
}
|
||||
binding.cutoutSpace.visibility = View.INVISIBLE
|
||||
binding.addButtonBackground.animate()
|
||||
.translationY(-binding.addButtonBackground.height.toFloat() / 2)
|
||||
.alpha(0.0f)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,126 @@ import android.graphics.PorterDuff
|
|||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.material.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.StatsViewBinding
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
import com.habitrpg.android.habitica.extensions.setTintWith
|
||||
import com.habitrpg.android.habitica.helpers.HapticFeedbackManager
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.common.habitica.extensions.layoutInflater
|
||||
|
||||
@Composable
|
||||
fun StatsViewComposable(
|
||||
statText: String,
|
||||
statColor: Color,
|
||||
levelValue: Int,
|
||||
equipmentValue: Int,
|
||||
buffValue: Int,
|
||||
allocatedValue: Int,
|
||||
canAllocate: Boolean,
|
||||
allocateAction: () -> Unit
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.background(colorResource(R.color.window_background))
|
||||
.clip(RoundedCornerShape(12.dp))) {
|
||||
Row(
|
||||
Modifier
|
||||
.height(43.dp)
|
||||
.fillMaxWidth()
|
||||
.background(statColor)
|
||||
.padding(horizontal = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(statText, color = colorResource(R.color.white))
|
||||
Text("${levelValue + equipmentValue + buffValue + allocatedValue}", color = colorResource(R.color.white))
|
||||
}
|
||||
Row(Modifier.height(61.dp),
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
verticalAlignment = Alignment.CenterVertically ) {
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.Center, Alignment.CenterHorizontally) {
|
||||
Text(text = "$levelValue", fontSize = 20.sp)
|
||||
Text(text = stringResource(R.string.level), color = colorResource(R.color.text_quad), fontSize = 12.sp)
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.Center, Alignment.CenterHorizontally) {
|
||||
Text(text = "$equipmentValue", fontSize = 20.sp)
|
||||
Text(text = stringResource(R.string.sidebar_equipment), color = colorResource(R.color.text_quad), fontSize = 12.sp)
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f), verticalArrangement = Arrangement.Center, Alignment.CenterHorizontally) {
|
||||
Text(text = "$buffValue", fontSize = 20.sp)
|
||||
Text(text = stringResource(R.string.buffs), color = colorResource(R.color.text_quad), fontSize = 12.sp)
|
||||
}
|
||||
Column(modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxHeight()
|
||||
.background(colorResource(if (canAllocate) R.color.offset_background_30 else R.color.window_background)), verticalArrangement = Arrangement.Center, Alignment.CenterHorizontally) {
|
||||
Text(text = "$allocatedValue", fontSize = 20.sp, color = if (canAllocate) statColor else colorResource(R.color.text_primary))
|
||||
Text(text = stringResource(R.string.allocated), color = if (canAllocate) statColor else colorResource(R.color.text_quad), fontSize = 12.sp)
|
||||
}
|
||||
AnimatedVisibility(visible = canAllocate) {
|
||||
TextButton(onClick = allocateAction,
|
||||
Modifier
|
||||
.width(48.dp)
|
||||
.fillMaxHeight()
|
||||
.background(
|
||||
colorResource(id = R.color.offset_background_30)
|
||||
)) {
|
||||
Image(HabiticaIconsHelper.imageOfAttributeAllocateButton().asImageBitmap(), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun StatsViewPreview() {
|
||||
Column(Modifier.background(colorResource(id = R.color.content_background))) {
|
||||
StatsViewComposable(
|
||||
statText = "Strength",
|
||||
statColor = colorResource(id = R.color.red_50),
|
||||
levelValue = 10,
|
||||
equipmentValue = 5,
|
||||
buffValue = 4,
|
||||
allocatedValue = 8,
|
||||
canAllocate = false
|
||||
) {}
|
||||
StatsViewComposable(
|
||||
statText = "Intelligence",
|
||||
statColor = colorResource(id = R.color.blue_50),
|
||||
levelValue = 10,
|
||||
equipmentValue = 5,
|
||||
buffValue = 4,
|
||||
allocatedValue = 8,
|
||||
canAllocate = true
|
||||
) {}
|
||||
}
|
||||
}
|
||||
|
||||
class StatsView(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
|
||||
private val binding = StatsViewBinding.inflate(context.layoutInflater, this, true)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@
|
|||
<color name="gray_600">#edecee</color>
|
||||
<color name="gray_700">#f9f9f9</color>
|
||||
|
||||
<color name="gray_1_30">#4D1A181D</color>
|
||||
|
||||
<color name="blue_1">#033f5e</color>
|
||||
<color name="teal_1">#005158</color>
|
||||
<color name="green_1">#005737</color>
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
NAME=4.0.3
|
||||
CODE=4571
|
||||
CODE=4581
|
||||