diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt index 1d0e34b28..bac4e94fd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DisplayItemDropUseCase.kt @@ -5,14 +5,14 @@ import androidx.appcompat.app.AppCompatActivity import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.executors.PostExecutionThread import com.habitrpg.android.habitica.helpers.SoundManager -import com.habitrpg.common.habitica.models.responses.TaskScoringResult import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar +import com.habitrpg.common.habitica.models.responses.TaskScoringResult import io.reactivex.rxjava3.core.Flowable -import javax.inject.Inject import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.MainScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import javax.inject.Inject class DisplayItemDropUseCase @Inject constructor(private val soundManager: SoundManager, postExecutionThread: PostExecutionThread) : UseCase(postExecutionThread) { @@ -22,14 +22,14 @@ constructor(private val soundManager: SoundManager, postExecutionThread: PostExe val data = requestValues.data val snackbarText = StringBuilder(data?.drop?.dialog ?: "") - if (data?.questItemsFound ?: 0 > 0 && requestValues.showQuestItems) { + if ((data?.questItemsFound ?: 0) > 0 && requestValues.showQuestItems) { if (snackbarText.isNotEmpty()) snackbarText.append('\n') snackbarText.append(requestValues.context.getString(R.string.quest_items_found, data!!.questItemsFound)) } if (snackbarText.isNotEmpty()) { - GlobalScope.launch(context = Dispatchers.Main) { + MainScope().launch(context = Dispatchers.Main) { delay(3000L) HabiticaSnackbar.showSnackbar( requestValues.snackbarTargetView, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt index 0539b94e6..e66a08d7d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ItemRecyclerAdapter.kt @@ -8,7 +8,6 @@ import androidx.fragment.app.DialogFragment import androidx.recyclerview.widget.RecyclerView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ItemItemBinding -import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.Food import com.habitrpg.android.habitica.models.inventory.HatchingPotion @@ -20,10 +19,11 @@ import com.habitrpg.android.habitica.models.user.OwnedItem import com.habitrpg.android.habitica.models.user.OwnedPet import com.habitrpg.android.habitica.models.user.User import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter -import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem import com.habitrpg.android.habitica.ui.views.dialogs.DetailDialog +import com.habitrpg.common.habitica.extensions.layoutInflater +import com.habitrpg.common.habitica.extensions.loadImage import io.reactivex.rxjava3.core.BackpressureStrategy import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.subjects.PublishSubject @@ -105,7 +105,7 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter 0) { + if (specialItem.isMysteryItem && (ownedItem?.numberOwned ?: 0) > 0) { menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.open))) - } else if (ownedItem?.numberOwned ?: 0 > 0) { + } else if ((ownedItem?.numberOwned ?: 0) > 0) { menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.use_item))) } } diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt index ba2d20ce5..6e6186e56 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskDirectionDataTemp.kt @@ -1,5 +1,8 @@ package com.habitrpg.common.habitica.models.responses +import android.os.Parcel +import android.os.Parcelable + class TaskDirectionDataTemp { var drop: TaskDirectionDataDrop? = null @@ -12,10 +15,37 @@ class TaskDirectionDataQuest { var collection: Int = 0 } -class TaskDirectionDataDrop { - +class TaskDirectionDataDrop() : Parcelable { var value: Int = 0 var key: String? = null var type: String? = null var dialog: String? = null + + constructor(parcel: Parcel) : this() { + value = parcel.readInt() + key = parcel.readString() + type = parcel.readString() + dialog = parcel.readString() + } + + override fun writeToParcel(parcel: Parcel, flags: Int) { + parcel.writeInt(value) + parcel.writeString(key) + parcel.writeString(type) + parcel.writeString(dialog) + } + + override fun describeContents(): Int { + return 0 + } + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(parcel: Parcel): TaskDirectionDataDrop { + return TaskDirectionDataDrop(parcel) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } } diff --git a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt index 15aad3a07..b3f51dc9f 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/models/responses/TaskScoringResult.kt @@ -8,10 +8,10 @@ class TaskScoringResult(): Parcelable { constructor(data: TaskDirectionData, stats: AvatarStats?) : this() { hasLeveledUp = data.lvl > (stats?.lvl ?: 0) healthDelta = data.hp - (stats?.hp ?: 0.0) - if (hasLeveledUp) { - experienceDelta = (stats?.toNextLevel ?: 0).toDouble() - (stats?.exp ?: 0.0) + data.exp + experienceDelta = if (hasLeveledUp) { + (stats?.toNextLevel ?: 0).toDouble() - (stats?.exp ?: 0.0) + data.exp } else { - experienceDelta = data.exp - (stats?.exp ?: 0.0) + data.exp - (stats?.exp ?: 0.0) } manaDelta = data.mp - (stats?.mp ?: 0.0) goldDelta = data.gp - (stats?.gp ?: 0.0) @@ -40,6 +40,7 @@ class TaskScoringResult(): Parcelable { level = parcel.readValue(Int::class.java.classLoader) as? Int questDamage = parcel.readValue(Double::class.java.classLoader) as? Double questItemsFound = parcel.readValue(Int::class.java.classLoader) as? Int + drop = parcel.readValue(TaskDirectionDataDrop::class.java.classLoader) as? TaskDirectionDataDrop } override fun writeToParcel(parcel: Parcel, flags: Int) { @@ -51,6 +52,7 @@ class TaskScoringResult(): Parcelable { parcel.writeValue(level) parcel.writeValue(questDamage) parcel.writeValue(questItemsFound) + parcel.writeValue(drop) } override fun describeContents(): Int { diff --git a/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt b/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt index 8bd65580f..6ab09431d 100644 --- a/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt +++ b/common/src/main/java/com/habitrpg/common/habitica/views/UsernameLabel.kt @@ -13,7 +13,9 @@ import androidx.core.content.ContextCompat import com.habitrpg.common.habitica.R import com.habitrpg.common.habitica.models.PlayerTier -class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) { +class UsernameLabel @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : LinearLayout(context, attrs) { private val textView = TextView(context) private val tierIconView = ImageView(context) @@ -54,7 +56,7 @@ class UsernameLabel(context: Context?, attrs: AttributeSet?) : LinearLayout(cont textViewParams.gravity = Gravity.CENTER_VERTICAL textViewParams.weight = 1.0f addView(textView, textViewParams) - val padding = context?.resources?.getDimension(R.dimen.spacing_small)?.toInt() ?: 0 + val padding = context.resources.getDimension(R.dimen.spacing_small).toInt() textView.setPadding(0, 0, padding, 0) textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14f) val iconViewParams = LayoutParams( diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt index f87ac8842..3d3151334 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/data/repositories/TaskRepository.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow import javax.inject.Inject -class TaskRepository @Inject constructor(val apiClient: ApiClient, val localRepository: TaskLocalRepository) { +class TaskRepository @Inject constructor(val apiClient: ApiClient, val localRepository: TaskLocalRepository, val userLocalRepository: UserLocalRepository) { suspend fun retrieveTasks(): TaskList? { val tasks = apiClient.getTasks() @@ -25,9 +25,36 @@ class TaskRepository @Inject constructor(val apiClient: ApiClient, val localRepo val result = apiClient.scoreTask(id, direction.text) if (result != null) { task.completed = direction == TaskDirection.UP + task.value += result.delta + if (task.type == TaskType.HABIT) { + if (direction == TaskDirection.UP) { + task.counterUp = task.counterUp?.plus(1) ?: 1 + } else { + task.counterUp = task.counterDown?.plus(1) ?: 1 + } + } else if (task.type == TaskType.DAILY) { + if (direction == TaskDirection.UP) { + task.streak = task.streak?.plus(1) ?: 1 + } else { + task.streak = task.streak?.minus(1) ?: 0 + } + } localRepository.updateTask(task) } - return result?.let { TaskScoringResult(it, user?.stats) } + val scoringResult = result?.let { TaskScoringResult(it, user?.stats) } + if (user != null) { + user.stats?.hp = result?.hp + user.stats?.exp = result?.exp + user.stats?.mp = result?.mp + user.stats?.gp = result?.gp + user.stats?.lvl = result?.lvl + /*user?.party?.quest?.progress?.up = ( + user?.party?.quest?.progress?.up + ?: 0F + ) + (result?._tmp?.quest?.progressDelta?.toFloat() ?: 0F)*/ + userLocalRepository.saveUser(user) + } + return scoringResult } fun getTask(taskID: String?): Flow { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskDetailActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskDetailActivity.kt index 03e9f282e..632fdb977 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskDetailActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskDetailActivity.kt @@ -2,14 +2,16 @@ package com.habitrpg.wearos.habitica.ui.activities import android.os.Bundle import androidx.activity.viewModels +import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ActivityTaskDetailBinding import com.habitrpg.wearos.habitica.ui.viewmodels.TaskDetailViewModel import dagger.hilt.android.AndroidEntryPoint import java.util.Locale @AndroidEntryPoint -class TaskDetailActivity: BaseActivity() { +class TaskDetailActivity : BaseActivity() { override val viewModel: TaskDetailViewModel by viewModels() @@ -29,15 +31,21 @@ class TaskDetailActivity: BaseActivity + binding.taskTypeView.text = task?.type?.value?.replaceFirstChar { if (it.isLowerCase()) it.titlecase( Locale.getDefault() ) else it.toString() } - binding.taskTextView.text = it?.text - if (it?.notes?.isNotBlank() == true) { - binding.taskNotesView.text = it.notes + binding.taskTypeView.setTextColor( + ContextCompat.getColor( + this, + task?.extraLightTaskColor ?: R.color.white + ) + ) + binding.taskTextView.text = task?.text + if (task?.notes?.isNotBlank() == true) { + binding.taskNotesView.text = task.notes binding.taskNotesView.isVisible = true } else { binding.taskNotesView.isVisible = false diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt index f8c7ac226..3cb3bcd00 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskFormActivity.kt @@ -28,8 +28,15 @@ class TaskFormActivity : BaseActivity R.string.habit + TaskType.DAILY -> R.string.daily + TaskType.TODO -> R.string.todo + TaskType.REWARD -> R.string.reward + else -> R.string.task + }) + binding.confirmationTitle.text = getString(R.string.new_task_x, typeName) + binding.saveButton.text = getString(R.string.save_task_x, typeName) } override val viewModel: TaskFormViewModel by viewModels() diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt index ee759ede2..dbe766bb1 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskResultActivity.kt @@ -12,6 +12,7 @@ import androidx.preference.PreferenceManager import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.ActivityTaskResultBinding import com.habitrpg.android.habitica.databinding.TaskRewardDropBinding +import com.habitrpg.android.habitica.extensions.localizedCapitalize import com.habitrpg.common.habitica.extensions.dpToPx import com.habitrpg.common.habitica.extensions.loadImage import com.habitrpg.common.habitica.models.responses.TaskScoringResult @@ -155,14 +156,16 @@ class TaskResultActivity : BaseActivity elements[0] 2 -> getString(R.string.x_and_y, elements[0], elements[1]) else -> elements.joinToString(", ") - } + }.localizedCapitalize() } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/adapters/HubAdapter.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/adapters/HubAdapter.kt index a80e0c627..ad6e00c22 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/adapters/HubAdapter.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/adapters/HubAdapter.kt @@ -2,9 +2,9 @@ package com.habitrpg.wearos.habitica.ui.adapters import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView -import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.android.habitica.databinding.RowHeaderBinding import com.habitrpg.android.habitica.databinding.RowHubBinding +import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.wearos.habitica.models.user.MenuItem import com.habitrpg.wearos.habitica.ui.viewHolders.HeaderViewHolder import com.habitrpg.wearos.habitica.ui.viewHolders.HubViewHolder @@ -27,19 +27,14 @@ class HubAdapter: RecyclerView.Adapter() { override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { if (holder is HubViewHolder) { - val item = data[position - 1] - holder.bind(item) + holder.bind(getItemAt(position - 1)) } else if (holder is HeaderViewHolder){ holder.bind(title) } } - override fun getItemViewType(position: Int): Int { - return if (position == 0) 0 else 1 - } - - override fun getItemCount(): Int { - return data.size + 1 - } + private fun getItemAt(position: Int) = data.filter { !it.isHidden }[position] + override fun getItemViewType(position: Int) = if (position == 0) 0 else 1 + override fun getItemCount() = data.filter { !it.isHidden }.size + 1 } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt index 370813a38..05de6fc91 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/DailyViewHolder.kt @@ -3,28 +3,15 @@ package com.habitrpg.wearos.habitica.ui.viewHolders.tasks import android.view.View import android.view.ViewGroup import android.widget.ImageView -import android.widget.TextView -import androidx.core.view.isVisible import com.habitrpg.android.habitica.databinding.RowDailyBinding -import com.habitrpg.wearos.habitica.models.tasks.Task +import com.habitrpg.wearos.habitica.ui.views.TaskTextView class DailyViewHolder(itemView: View) : CheckedTaskViewHolder(itemView) { private val binding = RowDailyBinding.bind(itemView) - override val titleView: TextView + override val titleView: TaskTextView get() = binding.title override val checkbox: ImageView get() = binding.checkbox override val checkboxWrapper: ViewGroup get() = binding.checkboxWrapper - - override fun bind(data: Task) { - super.bind(data) - val streakString = data.streakString - if (streakString?.isNotBlank() == true) { - binding.streakView.text = streakString - binding.streakView.isVisible = true - } else { - binding.streakView.isVisible = false - } - } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/HabitViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/HabitViewHolder.kt index e828837c1..9f938f21e 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/HabitViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/HabitViewHolder.kt @@ -2,16 +2,15 @@ package com.habitrpg.wearos.habitica.ui.viewHolders.tasks import android.content.res.ColorStateList import android.view.View -import android.widget.TextView -import androidx.core.view.isVisible import androidx.core.content.ContextCompat import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.databinding.RowHabitBinding import com.habitrpg.wearos.habitica.models.tasks.Task +import com.habitrpg.wearos.habitica.ui.views.TaskTextView class HabitViewHolder(itemView: View) : TaskViewHolder(itemView) { private val binding = RowHabitBinding.bind(itemView) - override val titleView: TextView + override val titleView: TaskTextView get() = binding.title init { @@ -43,12 +42,5 @@ class HabitViewHolder(itemView: View) : TaskViewHolder(itemView) { binding.habitButtonIcon.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, data.mediumTaskColor)) binding.habitButtonIcon.imageTintList = ColorStateList.valueOf(ContextCompat.getColor(itemView.context, R.color.white)) } - val streakString = data.streakString - if (streakString?.isNotBlank() == true) { - binding.streakView.text = streakString - binding.streakView.isVisible = true - } else { - binding.streakView.isVisible = false - } } } \ No newline at end of file diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/RewardViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/RewardViewHolder.kt index 3b8769c19..aa081eaa3 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/RewardViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/RewardViewHolder.kt @@ -4,10 +4,11 @@ import android.view.View import android.widget.TextView import com.habitrpg.android.habitica.databinding.RowRewardBinding import com.habitrpg.wearos.habitica.models.tasks.Task +import com.habitrpg.wearos.habitica.ui.views.TaskTextView class RewardViewHolder(itemView: View) : TaskViewHolder(itemView) { private val binding = RowRewardBinding.bind(itemView) - override val titleView: TextView + override val titleView: TaskTextView get() = binding.title override fun bind(data: Task) { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/TaskViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/TaskViewHolder.kt index 0a5ca0c18..9e345f954 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/TaskViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/TaskViewHolder.kt @@ -1,13 +1,13 @@ package com.habitrpg.wearos.habitica.ui.viewHolders.tasks import android.view.View -import android.widget.TextView import com.habitrpg.wearos.habitica.models.tasks.Task import com.habitrpg.wearos.habitica.ui.viewHolders.BindableViewHolder +import com.habitrpg.wearos.habitica.ui.views.TaskTextView abstract class TaskViewHolder(itemView: View) : BindableViewHolder(itemView) { var onTaskScore: (() -> Unit)? = null - abstract val titleView: TextView + abstract val titleView: TaskTextView override fun bind(data: Task) { titleView.text = data.text } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt index 81a8b95aa..7ef4f8594 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewHolders/tasks/ToDoViewHolder.kt @@ -5,10 +5,11 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import com.habitrpg.android.habitica.databinding.RowTodoBinding +import com.habitrpg.wearos.habitica.ui.views.TaskTextView class ToDoViewHolder(itemView: View) : CheckedTaskViewHolder(itemView) { private val binding = RowTodoBinding.bind(itemView) - override val titleView: TextView + override val titleView: TaskTextView get() = binding.title override val checkbox: ImageView get() = binding.checkbox diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt index eff5944c3..56268e902 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/HabiticaScrollView.kt @@ -23,7 +23,7 @@ class HabiticaScrollView @JvmOverloads constructor( horizontalPadding, verticalPadding, horizontalPadding, - verticalPadding + verticalPadding*2 ) } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskTextView.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskTextView.kt new file mode 100644 index 000000000..a6a691751 --- /dev/null +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/views/TaskTextView.kt @@ -0,0 +1,74 @@ +package com.habitrpg.wearos.habitica.ui.views + +import android.content.Context +import android.text.Spannable +import android.text.SpannableString +import android.text.SpannableStringBuilder +import android.text.TextUtils +import android.text.style.ForegroundColorSpan +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView +import com.habitrpg.android.habitica.R + +/** + * A custom [AppCompatTextView] that allows custom ellipsis and ellipsisColor. + */ +open class EllipsizedTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : AppCompatTextView(context, attrs, defStyleAttr) { + var ellipsis = getDefaultEllipsis().toString() + set(value) { + field = value + ellipsisSpannable = SpannableString(ellipsis) + } + var ellipsisColor = getDefaultEllipsisColor() + + private var ellipsisSpannable: SpannableString + private val spannableStringBuilder = SpannableStringBuilder() + + init { + if (attrs != null) { + val typedArray = context.theme.obtainStyledAttributes(attrs, R.styleable.EllipsizedTextView, 0, 0) + typedArray.let { + ellipsis = typedArray.getString(R.styleable.EllipsizedTextView_ellipsis) ?: getDefaultEllipsis().toString() + ellipsisColor = typedArray.getColor(R.styleable.EllipsizedTextView_ellipsisColor, getDefaultEllipsisColor()) + typedArray.recycle() + } + } + + ellipsisSpannable = SpannableString(ellipsis) + ellipsisSpannable.setSpan(ForegroundColorSpan(ellipsisColor), 0, ellipsis.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val availableScreenWidth = measuredWidth - compoundPaddingLeft.toFloat() - compoundPaddingRight.toFloat() + var availableTextWidth = availableScreenWidth * maxLines + var ellipsizedText = TextUtils.ellipsize(text, paint, availableTextWidth, ellipsize) + + if (ellipsizedText.toString() != text.toString()) { + // If the ellipsizedText is different than the original text, this means that it didn't fit and got indeed ellipsized. + // Calculate the new availableTextWidth by taking into consideration the size of the custom ellipsis, too. + availableTextWidth = (availableScreenWidth - paint.measureText(ellipsis)) * maxLines + ellipsizedText = TextUtils.ellipsize(text, paint, availableTextWidth, ellipsize) + val defaultEllipsisStart = ellipsizedText.indexOf(getDefaultEllipsis()) + val defaultEllipsisEnd = defaultEllipsisStart + 1 + + spannableStringBuilder.clear() + + // Update the text with the ellipsized version and replace the default ellipsis with the custom one. + text = spannableStringBuilder.append(ellipsizedText).replace(defaultEllipsisStart, defaultEllipsisEnd, ellipsisSpannable) + } + } + + private fun getDefaultEllipsis(): Char { + return Typography.ellipsis + } + + private fun getDefaultEllipsisColor(): Int { + return textColors.defaultColor + } +} + +class TaskTextView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null +) : EllipsizedTextView(context, attrs) { +} \ No newline at end of file diff --git a/wearos/src/main/res/layout/row_daily.xml b/wearos/src/main/res/layout/row_daily.xml index b2d3fa0b3..b4c171d79 100644 --- a/wearos/src/main/res/layout/row_daily.xml +++ b/wearos/src/main/res/layout/row_daily.xml @@ -26,20 +26,15 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> - - + android:maxLines="2" + android:ellipsize="end" + tools:text="Task Title that is long and wraps and" + android:textColor="@color/white" + style="@style/Text.Body1"/> \ No newline at end of file diff --git a/wearos/src/main/res/layout/row_habit.xml b/wearos/src/main/res/layout/row_habit.xml index b06dc6489..d703f998e 100644 --- a/wearos/src/main/res/layout/row_habit.xml +++ b/wearos/src/main/res/layout/row_habit.xml @@ -25,20 +25,15 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> - - \ No newline at end of file diff --git a/wearos/src/main/res/layout/row_reward.xml b/wearos/src/main/res/layout/row_reward.xml index f5167fb56..9437db75a 100644 --- a/wearos/src/main/res/layout/row_reward.xml +++ b/wearos/src/main/res/layout/row_reward.xml @@ -7,12 +7,14 @@ android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Chip"> - \ No newline at end of file diff --git a/wearos/src/main/res/layout/row_todo.xml b/wearos/src/main/res/layout/row_todo.xml index 9c00223bd..2916f4c8a 100644 --- a/wearos/src/main/res/layout/row_todo.xml +++ b/wearos/src/main/res/layout/row_todo.xml @@ -27,20 +27,15 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> - - \ No newline at end of file diff --git a/wearos/src/main/res/layout/task_reward_drop.xml b/wearos/src/main/res/layout/task_reward_drop.xml index 260ba6949..25a5c9a1b 100644 --- a/wearos/src/main/res/layout/task_reward_drop.xml +++ b/wearos/src/main/res/layout/task_reward_drop.xml @@ -16,6 +16,7 @@ android:layout_height="wrap_content" android:fontFamily="sans-serif-medium" android:textSize="14sp" + android:gravity="center" android:textColor="@color/white" /> + + + + \ No newline at end of file diff --git a/wearos/src/main/res/values/dimens.xml b/wearos/src/main/res/values/dimens.xml index 11068d2d1..b91229869 100644 --- a/wearos/src/main/res/values/dimens.xml +++ b/wearos/src/main/res/values/dimens.xml @@ -15,6 +15,6 @@ 16sp 10dp 9dp - 11dp + 10dp 2dp \ No newline at end of file