Continue group plan work

This commit is contained in:
Phillip Thelen 2022-10-04 09:33:18 +02:00
parent af21de48f5
commit ee20b4740f
30 changed files with 234 additions and 80 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,2 +1,2 @@
NAME=4.0.3
CODE=4571
CODE=4581