diff --git a/Habitica/res/drawable/bottom_sheet_background.xml b/Habitica/res/drawable/bottom_sheet_background.xml
new file mode 100644
index 000000000..811619d0d
--- /dev/null
+++ b/Habitica/res/drawable/bottom_sheet_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/drawable/bottom_sheet_title.xml b/Habitica/res/drawable/bottom_sheet_title.xml
index d33c4bc4c..73543f65b 100644
--- a/Habitica/res/drawable/bottom_sheet_title.xml
+++ b/Habitica/res/drawable/bottom_sheet_title.xml
@@ -2,4 +2,5 @@
+
diff --git a/Habitica/res/layout/bottom_sheet_wrapper.xml b/Habitica/res/layout/bottom_sheet_wrapper.xml
new file mode 100644
index 000000000..3f9dbdca8
--- /dev/null
+++ b/Habitica/res/layout/bottom_sheet_wrapper.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/layout/dialog_challenge_filter.xml b/Habitica/res/layout/dialog_challenge_filter.xml
index 0bdd075aa..c84ec77d9 100644
--- a/Habitica/res/layout/dialog_challenge_filter.xml
+++ b/Habitica/res/layout/dialog_challenge_filter.xml
@@ -1,28 +1,41 @@
-
-
-
-
+ xmlns:android="http://schemas.android.com/apk/res/android">
- android:orientation="vertical">
-
+
+
+
+
+ android:paddingStart="8dp"
+ android:paddingEnd="0dp"/>
+ android:paddingStart="8dp"
+ android:paddingEnd="0dp"/>
-
\ No newline at end of file
diff --git a/Habitica/res/layout/dialog_task_filter.xml b/Habitica/res/layout/dialog_task_filter.xml
index 3a191934e..1296ca1da 100644
--- a/Habitica/res/layout/dialog_task_filter.xml
+++ b/Habitica/res/layout/dialog_task_filter.xml
@@ -4,7 +4,38 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginBottom="16dp">
+ android:layout_marginBottom="16dp"
+ android:paddingStart="@dimen/bottom_sheet_inset"
+ android:paddingEnd="@dimen/bottom_sheet_inset">
+
+
+
+
+
+
+ android:clickable="false">
5dp
4dp
10dp
+ 20dp
+ 16dp
diff --git a/Habitica/res/values/styles.xml b/Habitica/res/values/styles.xml
index d36ed3402..9cdafe318 100644
--- a/Habitica/res/values/styles.xml
+++ b/Habitica/res/values/styles.xml
@@ -845,5 +845,40 @@
- bold
+
+
+
+
+
+
+
12dp
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
index 35786e64c..aa0a9afb0 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
@@ -8,7 +8,6 @@ import android.view.animation.AccelerateInterpolator
import android.widget.FrameLayout
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
-import com.google.android.material.bottomsheet.BottomSheetDialog
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.InventoryRepository
@@ -20,6 +19,7 @@ import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.ui.helpers.loadImage
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
+import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
import com.plattysoft.leonids.ParticleSystem
import javax.inject.Inject
@@ -166,7 +166,7 @@ class ArmoireActivity: BaseActivity() {
}
fun showDropRateDialog() {
- val dialog = BottomSheetDialog(this)
+ val dialog = HabiticaBottomSheetDialog(this)
dialog.setContentView(R.layout.armoire_drop_rate_dialog)
dialog.show()
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt
index 76e990ba8..451d9bc88 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/BaseDialogFragment.kt
@@ -4,8 +4,8 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.habitrpg.android.habitica.HabiticaBaseApplication
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.TutorialRepository
@@ -18,7 +18,7 @@ import io.reactivex.rxjava3.functions.Consumer
import java.util.concurrent.TimeUnit
import javax.inject.Inject
-abstract class BaseDialogFragment : DialogFragment() {
+abstract class BaseDialogFragment : BottomSheetDialogFragment() {
var isModal: Boolean = false
abstract var binding: VB?
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt
index 973dc8ebb..34f97aeda 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeFilterDialogHolder.kt
@@ -8,6 +8,7 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.DialogChallengeFilterBinding
import com.habitrpg.android.habitica.models.social.Group
import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengesFilterRecyclerViewAdapter
+import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
import com.habitrpg.android.habitica.utils.Action1
internal class ChallengeFilterDialogHolder private constructor(
@@ -28,13 +29,10 @@ internal class ChallengeFilterDialogHolder private constructor(
}
fun bind(
- builder: AlertDialog.Builder,
filterGroups: List,
currentFilter: ChallengeFilterOptions?,
selectedGroupsCallback: Action1
) {
- builder.setPositiveButton(context.getString(R.string.done)) { _, _ -> doneClicked() }
- .show()
this.filterGroups = filterGroups
this.currentFilter = currentFilter
this.selectedGroupsCallback = selectedGroupsCallback
@@ -86,11 +84,11 @@ internal class ChallengeFilterDialogHolder private constructor(
val challengeFilterDialogHolder = ChallengeFilterDialogHolder(dialogLayout, activity)
- val builder = AlertDialog.Builder(activity)
- .setTitle(R.string.filter)
- .setView(dialogLayout)
+ val sheet = HabiticaBottomSheetDialog(activity)
+ sheet.setContentView(dialogLayout)
- challengeFilterDialogHolder.bind(builder, filterGroups, currentFilter, selectedGroupsCallback)
+ challengeFilterDialogHolder.bind(filterGroups, currentFilter, selectedGroupsCallback)
+ sheet.show()
}
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/menu/BottomSheetMenu.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/menu/BottomSheetMenu.kt
index 2bf3e8fc5..a7dbbcf7c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/menu/BottomSheetMenu.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/menu/BottomSheetMenu.kt
@@ -2,21 +2,16 @@ package com.habitrpg.android.habitica.ui.menu
import android.content.Context
import android.view.View
-import com.google.android.material.bottomsheet.BottomSheetBehavior
-import com.google.android.material.bottomsheet.BottomSheetDialog
import com.habitrpg.android.habitica.databinding.MenuBottomSheetBinding
+import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
-class BottomSheetMenu(context: Context) : BottomSheetDialog(context), View.OnClickListener {
+class BottomSheetMenu(context: Context) : HabiticaBottomSheetDialog(context), View.OnClickListener {
private var binding = MenuBottomSheetBinding.inflate(layoutInflater)
private var runnable: ((Int) -> Unit)? = null
init {
setContentView(binding.root)
binding.titleView.visibility = View.GONE
-
- val behavior = BottomSheetBehavior.from(binding.root.parent as View)
- behavior.state = BottomSheetBehavior.STATE_EXPANDED
- behavior.peekHeight = 0
}
fun setSelectionRunnable(runnable: (Int) -> Unit) {
@@ -26,12 +21,14 @@ class BottomSheetMenu(context: Context) : BottomSheetDialog(context), View.OnCli
override fun setTitle(title: CharSequence?) {
binding.titleView.text = title
binding.titleView.visibility = View.VISIBLE
+ grabberVisibility = View.GONE
}
fun addMenuItem(menuItem: BottomSheetMenuItem) {
val item = menuItem.inflate(this.context, layoutInflater, this.binding.menuItems)
item.setOnClickListener(this)
this.binding.menuItems.addView(item)
+ binding.root.requestLayout()
}
override fun onClick(v: View) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaBottomDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaBottomDialog.kt
new file mode 100644
index 000000000..57aa9fb32
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/HabiticaBottomDialog.kt
@@ -0,0 +1,27 @@
+package com.habitrpg.android.habitica.ui.views.dialogs
+
+import android.content.Context
+import android.view.View
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.databinding.BottomSheetWrapperBinding
+
+open class HabiticaBottomSheetDialog(context: Context) : BottomSheetDialog(context, R.style.SheetDialog) {
+ private val wrapperBinding = BottomSheetWrapperBinding.inflate(layoutInflater)
+
+ var grabberVisibility: Int
+ get() = wrapperBinding.grabber.visibility
+ set(value) {
+ wrapperBinding.grabber.visibility = value
+ }
+
+ override fun setContentView(view: View) {
+ wrapperBinding.container.addView(view)
+ super.setContentView(wrapperBinding.root)
+ }
+
+ override fun setContentView(layoutResId: Int) {
+ layoutInflater.inflate(layoutResId, wrapperBinding.container)
+ super.setContentView(wrapperBinding.root)
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt
index 876b0374a..3b540e446 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/TaskFilterDialog.kt
@@ -12,9 +12,7 @@ import android.widget.Button
import android.widget.EditText
import android.widget.ImageButton
import android.widget.LinearLayout
-import android.widget.RadioButton
import android.widget.RadioGroup
-import android.widget.TextView
import androidx.annotation.IdRes
import androidx.appcompat.widget.AppCompatCheckBox
import androidx.core.content.ContextCompat
@@ -22,32 +20,24 @@ import androidx.core.widget.CompoundButtonCompat
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.TagRepository
+import com.habitrpg.android.habitica.databinding.DialogTaskFilterBinding
import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher
import com.habitrpg.android.habitica.extensions.getThemeColor
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.Tag
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.models.tasks.TaskType
-import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
+import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaBottomSheetDialog
import io.reactivex.rxjava3.core.Observable
import java.util.UUID
import javax.inject.Inject
-class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAlertDialog(context), RadioGroup.OnCheckedChangeListener {
-
- private var clearButton: Button
+class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaBottomSheetDialog(context), RadioGroup.OnCheckedChangeListener {
+ private val binding = DialogTaskFilterBinding.inflate(layoutInflater)
@Inject
lateinit var repository: TagRepository
- private var taskTypeTitle: TextView
- private var taskFilters: RadioGroup
- private var allTaskFilter: RadioButton
- private var secondTaskFilter: RadioButton
- private var thirdTaskFilter: RadioButton
- private var tagsEditButton: Button
- private var tagsList: LinearLayout
-
private var taskType: TaskType? = null
private var listener: OnFilterCompletedListener? = null
@@ -65,22 +55,12 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
component?.inject(this)
addIcon = ContextCompat.getDrawable(context, R.drawable.ic_add_purple_300_36dp)
- val inflater = LayoutInflater.from(context)
- val view = inflater.inflate(R.layout.dialog_task_filter, null)
setTitle(R.string.filters)
- this.setAdditionalContentView(view)
+ this.setContentView(binding.root)
- taskTypeTitle = view.findViewById(R.id.task_type_title)
- taskFilters = view.findViewById(R.id.task_filter_wrapper)
- allTaskFilter = view.findViewById(R.id.all_task_filter)
- secondTaskFilter = view.findViewById(R.id.second_task_filter)
- thirdTaskFilter = view.findViewById(R.id.third_task_filter)
- tagsEditButton = view.findViewById(R.id.tag_edit_button)
- tagsList = view.findViewById(R.id.tags_list)
+ binding.taskFilterWrapper.setOnCheckedChangeListener(this)
- taskFilters.setOnCheckedChangeListener(this)
-
- clearButton = addButton(R.string.clear, false, false, false) { _, _ ->
+ binding.clearButton.setOnClickListener {
if (isEditing) {
stopEditing()
}
@@ -88,16 +68,12 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
setActiveTags(null)
}
- addButton(R.string.done, false) { _, _ ->
- if (isEditing) {
- stopEditing()
- }
- listener?.onFilterCompleted(filterType, activeTags)
- this.dismiss()
- }
- buttonAxis = LinearLayout.HORIZONTAL
+ binding.tagEditButton.setOnClickListener { editButtonClicked() }
+ }
- tagsEditButton.setOnClickListener { editButtonClicked() }
+ override fun dismiss() {
+ listener?.onFilterCompleted(filterType, activeTags)
+ super.dismiss()
}
override fun show() {
@@ -111,7 +87,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
private fun createTagViews() {
- tagsList.removeAllViews()
+ binding.tagsList.removeAllViews()
val colorStateList = ColorStateList(
arrayOf(
intArrayOf(-android.R.attr.state_checked), // disabled
@@ -149,7 +125,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
filtersChanged()
}
- tagsList.addView(tagCheckbox)
+ binding.tagsList.addView(tagCheckbox)
}
createAddTagButton()
}
@@ -164,7 +140,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
button.setBackgroundResource(R.drawable.layout_rounded_bg_lighter_gray)
button.setTextColor(ContextCompat.getColor(context, R.color.text_secondary))
- tagsList.addView(button)
+ binding.tagsList.addView(button)
}
private fun createTag() {
@@ -177,17 +153,17 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
private fun startEditing() {
isEditing = true
- tagsList.removeAllViews()
+ binding.tagsList.removeAllViews()
createTagEditViews()
- tagsEditButton.setText(R.string.done)
+ binding.tagEditButton.setText(R.string.done)
this.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
}
private fun stopEditing() {
isEditing = false
- tagsList.removeAllViews()
+ binding.tagsList.removeAllViews()
createTagViews()
- tagsEditButton.setText(R.string.edit_tag_btn_edit)
+ binding.tagEditButton.setText(R.string.edit_tag_btn_edit)
this.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
repository.updateTags(editedTags.values).toObservable().flatMap { tags -> Observable.fromIterable(tags) }.subscribe({ tag -> editedTags.remove(tag.id) }, RxErrorHandler.handleEmptyError())
repository.createTags(createdTags.values).toObservable().flatMap { tags -> Observable.fromIterable(tags) }.subscribe({ tag -> createdTags.remove(tag.id) }, RxErrorHandler.handleEmptyError())
@@ -204,7 +180,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
private fun createTagEditView(inflater: LayoutInflater, index: Int, tag: Tag) {
- val wrapper = inflater.inflate(R.layout.edit_tag_item, tagsList, false) as? LinearLayout
+ val wrapper = inflater.inflate(R.layout.edit_tag_item, binding.tagsList, false) as? LinearLayout
val tagEditText = wrapper?.findViewById(R.id.edit_text) as? EditText
tagEditText?.setText(tag.name)
tagEditText?.addTextChangedListener(
@@ -233,9 +209,9 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
activeTags.remove(tag.id)
tags.remove(tag)
- tagsList.removeView(wrapper)
+ binding.tagsList.removeView(wrapper)
}
- tagsList.addView(wrapper)
+ binding.tagsList.addView(wrapper)
}
fun setActiveTags(tagIds: MutableList?) {
@@ -244,13 +220,13 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
} else {
this.activeTags = tagIds
}
- for (index in 0 until tagsList.childCount - 1) {
- (tagsList.getChildAt(index) as? AppCompatCheckBox)?.isChecked = false
+ for (index in 0 until binding.tagsList.childCount - 1) {
+ (binding.tagsList.getChildAt(index) as? AppCompatCheckBox)?.isChecked = false
}
for (tagId in this.activeTags) {
val index = indexForId(tagId)
if (index >= 0) {
- (tagsList.getChildAt(index) as? AppCompatCheckBox)?.isChecked = true
+ (binding.tagsList.getChildAt(index) as? AppCompatCheckBox)?.isChecked = true
}
}
filtersChanged()
@@ -269,22 +245,22 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
this.taskType = taskType
when (taskType) {
TaskType.HABIT -> {
- taskTypeTitle.setText(R.string.habits)
- allTaskFilter.setText(R.string.all)
- secondTaskFilter.setText(R.string.weak)
- thirdTaskFilter.setText(R.string.strong)
+ binding.taskTypeTitle.setText(R.string.habits)
+ binding.allTaskFilter.setText(R.string.all)
+ binding.secondTaskFilter.setText(R.string.weak)
+ binding.thirdTaskFilter.setText(R.string.strong)
}
TaskType.DAILY -> {
- taskTypeTitle.setText(R.string.dailies)
- allTaskFilter.setText(R.string.all)
- secondTaskFilter.setText(R.string.due)
- thirdTaskFilter.setText(R.string.gray)
+ binding.taskTypeTitle.setText(R.string.dailies)
+ binding.allTaskFilter.setText(R.string.all)
+ binding.secondTaskFilter.setText(R.string.due)
+ binding.thirdTaskFilter.setText(R.string.gray)
}
TaskType.TODO -> {
- taskTypeTitle.setText(R.string.todos)
- allTaskFilter.setText(R.string.active)
- secondTaskFilter.setText(R.string.dated)
- thirdTaskFilter.setText(R.string.completed)
+ binding.taskTypeTitle.setText(R.string.todos)
+ binding.allTaskFilter.setText(R.string.active)
+ binding.secondTaskFilter.setText(R.string.dated)
+ binding.thirdTaskFilter.setText(R.string.completed)
}
}
setActiveFilter(activeFilter)
@@ -307,7 +283,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
}
}
- taskFilters.check(checkedId)
+ binding.taskFilterWrapper.check(checkedId)
filtersChanged()
}
@@ -345,9 +321,9 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
private fun filtersChanged() {
- clearButton.isEnabled = hasActiveFilters()
- clearButton.setTextColor(
- if (clearButton.isEnabled) {
+ binding.clearButton.isEnabled = hasActiveFilters()
+ binding.clearButton.setTextColor(
+ if (binding.clearButton.isEnabled) {
context.getThemeColor(R.attr.colorAccent)
} else {
ContextCompat.getColor(context, R.color.text_dimmed)
@@ -356,7 +332,7 @@ class TaskFilterDialog(context: Context, component: UserComponent?) : HabiticaAl
}
private fun hasActiveFilters(): Boolean {
- return taskFilters.checkedRadioButtonId != R.id.all_task_filter || activeTags.size > 0
+ return binding.taskFilterWrapper.checkedRadioButtonId != R.id.all_task_filter || activeTags.size > 0
}
fun setListener(listener: OnFilterCompletedListener) {