diff --git a/Habitica/AndroidManifest.xml b/Habitica/AndroidManifest.xml
index 166a4dddc..5aa83f69e 100644
--- a/Habitica/AndroidManifest.xml
+++ b/Habitica/AndroidManifest.xml
@@ -110,6 +110,15 @@
android:name=".ui.activities.AboutActivity"
android:theme="@style/AppThemeWithActionBarBlackText"
android:screenOrientation="portrait"/>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/drawable/habit_scoring_circle_selected.xml b/Habitica/res/drawable/habit_scoring_circle_selected.xml
new file mode 100644
index 000000000..c42816052
--- /dev/null
+++ b/Habitica/res/drawable/habit_scoring_circle_selected.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/drawable/layout_rounded_bg_task_form.xml b/Habitica/res/drawable/layout_rounded_bg_task_form.xml
new file mode 100644
index 000000000..a9bd8afc2
--- /dev/null
+++ b/Habitica/res/drawable/layout_rounded_bg_task_form.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/drawable/tag_divider.xml b/Habitica/res/drawable/tag_divider.xml
new file mode 100644
index 000000000..ca6ccf468
--- /dev/null
+++ b/Habitica/res/drawable/tag_divider.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/layout/activity_task_form.xml b/Habitica/res/layout/activity_task_form.xml
index 685c1a873..2cfebee45 100644
--- a/Habitica/res/layout/activity_task_form.xml
+++ b/Habitica/res/layout/activity_task_form.xml
@@ -1,390 +1,199 @@
-
+
-
-
+
+
+
+
+
+
-
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+ tools:background="@color/brand_300"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/spacing_large"
+ android:paddingEnd="@dimen/spacing_large"
+ android:paddingBottom="@dimen/spacing_large">
+
+
+
+
+
+
+
+ android:layout_marginStart="@dimen/spacing_large"
+ android:layout_marginEnd="@dimen/spacing_large">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/Habitica/res/layout/activity_task_form_old.xml b/Habitica/res/layout/activity_task_form_old.xml
new file mode 100644
index 000000000..685c1a873
--- /dev/null
+++ b/Habitica/res/layout/activity_task_form_old.xml
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Habitica/res/layout/task_form_habit_scoring.xml b/Habitica/res/layout/task_form_habit_scoring.xml
new file mode 100644
index 000000000..ade704ff5
--- /dev/null
+++ b/Habitica/res/layout/task_form_habit_scoring.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/layout/task_form_task_difficulty.xml b/Habitica/res/layout/task_form_task_difficulty.xml
new file mode 100644
index 000000000..fea15bd67
--- /dev/null
+++ b/Habitica/res/layout/task_form_task_difficulty.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/menu/menu_full_profile.xml b/Habitica/res/menu/menu_full_profile.xml
index fdb3e8d45..2bef74025 100644
--- a/Habitica/res/menu/menu_full_profile.xml
+++ b/Habitica/res/menu/menu_full_profile.xml
@@ -1,8 +1,7 @@
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 093c25d1d..d414d0705 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -102,8 +102,8 @@
Medium
Hard
Start Date
- Positive ( + )
- Negative ( - )
+ Positive
+ Negative
Checklist
Reminders
Actions
@@ -866,8 +866,13 @@
Only leader can create Challenges
Create Party
Add Local Authentication
+ Task Title
+
Old Password
New Password
Repeat new Password
-
+ Adjust Streak
+ Assigned Stat
+ Monthly
+ Weekly
diff --git a/Habitica/res/values/styles.xml b/Habitica/res/values/styles.xml
index ca27f5c34..83422e781 100644
--- a/Habitica/res/values/styles.xml
+++ b/Habitica/res/values/styles.xml
@@ -33,9 +33,14 @@
- false
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #99edecee
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
index 141fa83d6..1527ef84a 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/components/AppComponent.java
@@ -34,6 +34,7 @@ import com.habitrpg.android.habitica.ui.activities.SetupActivity;
import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity;
import com.habitrpg.android.habitica.ui.activities.SkillTasksActivity;
import com.habitrpg.android.habitica.ui.activities.OldTaskFormActivity;
+import com.habitrpg.android.habitica.ui.activities.TaskFormActivity;
import com.habitrpg.android.habitica.ui.activities.VerifyUsernameActivity;
import com.habitrpg.android.habitica.ui.adapter.social.challenges.ChallengeTasksRecyclerViewAdapter;
import com.habitrpg.android.habitica.ui.adapter.tasks.DailiesRecyclerViewHolder;
@@ -311,4 +312,6 @@ public interface AppComponent {
void inject(@NotNull AboutFragment aboutFragment);
void inject(@NotNull ChatBarView chatBarView);
+
+ void inject(@NotNull TaskFormActivity taskFormActivity);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TagRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TagRepository.kt
index af07ad6f6..519e2dba5 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TagRepository.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TagRepository.kt
@@ -8,6 +8,7 @@ import io.realm.RealmResults
interface TagRepository : BaseRepository {
+ fun getTags(): Flowable>
fun getTags(userId: String): Flowable>
fun createTag(tag: Tag): Flowable
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TagRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TagRepositoryImpl.kt
index c94b51837..3cbe73bc0 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TagRepositoryImpl.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TagRepositoryImpl.kt
@@ -11,6 +11,10 @@ import io.realm.RealmResults
class TagRepositoryImpl(localRepository: TagLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl(localRepository, apiClient, userID), TagRepository {
+ override fun getTags(): Flowable> {
+ return getTags(userID)
+ }
+
override fun getTags(userId: String): Flowable> {
return localRepository.getTags(userId)
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
index 7658f5c27..baf897de3 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
@@ -140,29 +140,6 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
return Flowable.empty()
}
lastTaskAction = now
- task.tags?.let {
- if (it.size > 0) {
- val tags = RealmList()
- tags.addAll(localRepository.getUnmanagedCopy(it))
- task.tags = tags
- }
- }
-
- task.checklist?.let {
- if (it.size > 0) {
- val checklist = RealmList()
- checklist.addAll(localRepository.getUnmanagedCopy(it))
- task.checklist = checklist
- }
- }
-
- task.reminders?.let {
- if (it.size > 0) {
- val reminders = RealmList()
- reminders.addAll(localRepository.getUnmanagedCopy(it))
- task.reminders = reminders
- }
- }
task.isSaving = true
task.isCreating = true
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Bitmap-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Bitmap-Extensions.kt
new file mode 100644
index 000000000..54087f50a
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Bitmap-Extensions.kt
@@ -0,0 +1,11 @@
+package com.habitrpg.android.habitica.extensions
+
+import android.content.res.Resources
+import android.graphics.Bitmap
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+
+
+fun Bitmap.asDrawable(resources: Resources): Drawable {
+ return BitmapDrawable(resources, this)
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/HabitResetOption.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/HabitResetOption.kt
new file mode 100644
index 000000000..4b309476a
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/HabitResetOption.kt
@@ -0,0 +1,10 @@
+package com.habitrpg.android.habitica.models.tasks
+
+import androidx.annotation.StringRes
+import com.habitrpg.android.habitica.R
+
+enum class HabitResetOption(val value: String, @StringRes val nameRes: Int) {
+ DAILY("daily", R.string.daily),
+ WEEKLY("weekly", R.string.weekly),
+ MONTHLY("monthly", R.string.monthly)
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskDifficulty.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskDifficulty.kt
new file mode 100644
index 000000000..b8df82126
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/tasks/TaskDifficulty.kt
@@ -0,0 +1,10 @@
+package com.habitrpg.android.habitica.models.tasks
+
+import com.habitrpg.android.habitica.R
+
+enum class TaskDifficulty(val value: Float, val nameRes: Int) {
+ TRIVIAL(0.1f, R.string.trivial),
+ EASY(1f, R.string.easy),
+ MEDIUM(1.5f, R.string.medium),
+ HARD(2f, R.string.hard)
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt
new file mode 100644
index 000000000..295016c78
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt
@@ -0,0 +1,298 @@
+package com.habitrpg.android.habitica.ui.activities
+
+import android.content.Context
+import android.os.Bundle
+import android.view.Menu
+import android.view.View
+import android.view.ViewGroup
+import android.widget.CheckBox
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.appcompat.widget.Toolbar
+import androidx.core.content.ContextCompat
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.components.AppComponent
+import com.habitrpg.android.habitica.data.TagRepository
+import com.habitrpg.android.habitica.data.TaskRepository
+import com.habitrpg.android.habitica.data.UserRepository
+import com.habitrpg.android.habitica.extensions.notNull
+import com.habitrpg.android.habitica.helpers.RxErrorHandler
+import com.habitrpg.android.habitica.models.Tag
+import com.habitrpg.android.habitica.models.tasks.HabitResetOption
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.Stats
+import com.habitrpg.android.habitica.ui.helpers.bindView
+import com.habitrpg.android.habitica.ui.views.tasks.form.HabitResetStreakButtons
+import com.habitrpg.android.habitica.ui.views.tasks.form.HabitScoringButtonsView
+import com.habitrpg.android.habitica.ui.views.tasks.form.TaskDifficultyButtons
+import io.reactivex.functions.Consumer
+import javax.inject.Inject
+import android.content.res.ColorStateList
+import android.graphics.drawable.ColorDrawable
+import android.view.MenuItem
+import android.view.inputmethod.InputMethodManager
+import androidx.appcompat.widget.AppCompatCheckBox
+import androidx.core.view.children
+import androidx.core.view.forEach
+import androidx.core.view.forEachIndexed
+import com.habitrpg.android.habitica.extensions.dpToPx
+import io.realm.RealmList
+
+
+class TaskFormActivity : BaseActivity() {
+
+ @Inject
+ lateinit var userRepository: UserRepository
+ @Inject
+ lateinit var taskRepository: TaskRepository
+ @Inject
+ lateinit var tagRepository: TagRepository
+
+ private val toolbar: Toolbar by bindView(R.id.toolbar)
+ private val upperTextWrapper: LinearLayout by bindView(R.id.upper_text_wrapper)
+ private val textEditText: EditText by bindView(R.id.text_edit_text)
+ private val notesEditText: EditText by bindView(R.id.notes_edit_text)
+ private val habitScoringButtons: HabitScoringButtonsView by bindView(R.id.habit_scoring_buttons)
+ private val habitResetStreakTitleView: TextView by bindView(R.id.habit_reset_streak_title)
+ private val habitResetStreakButtons: HabitResetStreakButtons by bindView(R.id.habit_reset_streak_buttons)
+ private val adjustStreakWrapper: ViewGroup by bindView(R.id.adjust_streak_wrapper)
+ private val adjustStreakTitleView: TextView by bindView(R.id.adjust_streak_title)
+ private val habitAdjustPositiveStreakView: EditText by bindView(R.id.habit_adjust_positive_streak)
+ private val habitAdjustNegativeStreakView: EditText by bindView(R.id.habit_adjust_negative_streak)
+
+ private val taskDifficultyButtons: TaskDifficultyButtons by bindView(R.id.task_difficulty_buttons)
+
+ private val statWrapper: ViewGroup by bindView(R.id.stat_wrapper)
+ private val statStrengthButton: TextView by bindView(R.id.stat_strength_button)
+ private val statIntelligenceButton: TextView by bindView(R.id.stat_intelligence_button)
+ private val statConstitutionButton: TextView by bindView(R.id.stat_constitution_button)
+ private val statPerceptionButton: TextView by bindView(R.id.stat_perception_button)
+
+ private val tagsWrapper: LinearLayout by bindView(R.id.tags_wrapper)
+
+ private var isCreating = true
+ private var usesTaskAttributeStats = false
+ private var task: Task? = null
+ private var taskType: String = ""
+ private var tags = listOf()
+ private var selectedStat = Stats.STRENGTH
+ set(value) {
+ field = value
+ setSelectedAttribute(value)
+ }
+
+ private var tintColor: Int = 0
+ set(value) {
+ field = value
+ upperTextWrapper.setBackgroundColor(value)
+ taskDifficultyButtons.tintColor = value
+ habitScoringButtons.tintColor = value
+ habitResetStreakButtons.tintColor = value
+ supportActionBar?.setBackgroundDrawable(ColorDrawable(value))
+ updateTagViewsColors()
+ }
+
+ override fun getLayoutResId(): Int {
+ return R.layout.activity_task_form
+ }
+
+ override fun injectActivity(component: AppComponent?) {
+ component?.inject(this)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setSupportActionBar(toolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ supportActionBar?.setDisplayShowHomeEnabled(true)
+ title = ""
+ tintColor = ContextCompat.getColor(this, R.color.brand_300)
+
+ val bundle = intent.extras ?: return
+
+ taskType = bundle.getString(OldTaskFormActivity.TASK_TYPE_KEY) ?: Task.TYPE_HABIT
+ val taskId = bundle.getString(OldTaskFormActivity.TASK_ID_KEY)
+ if (taskId != null) {
+ isCreating = false
+ compositeSubscription.add(taskRepository.getUnmanagedTask(taskId).subscribe(Consumer {
+ task = it
+ //tintColor = ContextCompat.getColor(this, it.mediumTaskColor)
+ fillForm(it)
+ }, RxErrorHandler.handleEmptyError()))
+ }
+
+ compositeSubscription.add(tagRepository.getTags()
+ .map { tagRepository.getUnmanagedCopy(it) }
+ .subscribe(Consumer {
+ tags = it
+ setTagViews()
+ }, RxErrorHandler.handleEmptyError()))
+ compositeSubscription.add(userRepository.getUser().subscribe(Consumer {
+ usesTaskAttributeStats = it.preferences?.allocationMode == "taskbased"
+ configureForm()
+ }, RxErrorHandler.handleEmptyError()))
+
+ statStrengthButton.setOnClickListener { selectedStat = Stats.STRENGTH }
+ statIntelligenceButton.setOnClickListener { selectedStat = Stats.INTELLIGENCE }
+ statConstitutionButton.setOnClickListener { selectedStat = Stats.CONSTITUTION }
+ statPerceptionButton.setOnClickListener { selectedStat = Stats.PERCEPTION }
+
+ configureForm()
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ if (isCreating) {
+ menuInflater.inflate(R.menu.menu_task_create, menu)
+ } else {
+ menuInflater.inflate(R.menu.menu_task_edit, menu)
+ }
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem?): Boolean {
+ when (item?.itemId) {
+ R.id.action_create -> saveTask()
+ R.id.action_save_changes -> saveTask()
+ R.id.action_delete -> deleteTask()
+ }
+ return super.onOptionsItemSelected(item)
+ }
+
+ private fun configureForm() {
+ val habitViewsVisibility = if (taskType == Task.TYPE_HABIT) View.VISIBLE else View.GONE
+ habitScoringButtons.visibility = habitViewsVisibility
+ habitResetStreakTitleView.visibility = habitViewsVisibility
+ habitResetStreakButtons.visibility = habitViewsVisibility
+ habitAdjustPositiveStreakView.visibility = habitViewsVisibility
+ habitAdjustNegativeStreakView.visibility = habitViewsVisibility
+
+ val dailyViewsVisibility = if (taskType == Task.TYPE_DAILY) View.VISIBLE else View.GONE
+ val todoViewsVisibility = if (taskType == Task.TYPE_TODO) View.VISIBLE else View.GONE
+
+ statWrapper.visibility = if (usesTaskAttributeStats) View.VISIBLE else View.GONE
+ if (isCreating) {
+ adjustStreakTitleView.visibility = View.GONE
+ adjustStreakWrapper.visibility = View.GONE
+ }
+ }
+
+ private fun setTagViews() {
+ tagsWrapper.removeAllViews()
+ val padding = 20.dpToPx(this)
+ for (tag in tags) {
+ val view = CheckBox(this)
+ view.setPadding(padding, view.paddingTop, view.paddingRight, view.paddingBottom)
+ view.text = tag.name
+ tagsWrapper.addView(view)
+ }
+ setAllTagSelections()
+ updateTagViewsColors()
+ }
+
+ private fun setAllTagSelections() {
+ tags.forEachIndexed { index, tag ->
+ val view = tagsWrapper.getChildAt(index) as? CheckBox
+ view?.isChecked = task?.tags?.find { it.id == tag.id } != null
+ }
+ }
+
+ private fun fillForm(task: Task) {
+ textEditText.setText(task.text)
+ notesEditText.setText(task.notes)
+ taskDifficultyButtons.selectedDifficulty = task.priority
+ if (taskType == Task.TYPE_HABIT) {
+ habitScoringButtons.isPositive = task.up ?: false
+ habitScoringButtons.isNegative = task.down ?: false
+ task.frequency?.let { habitResetStreakButtons.selectedResetOption = HabitResetOption.valueOf(it.toUpperCase()) }
+ habitAdjustPositiveStreakView.setText((task.counterUp ?: 0).toString())
+ habitAdjustNegativeStreakView.setText((task.counterDown ?: 0).toString())
+ }
+ task.attribute?.let { setSelectedAttribute(it) }
+ setAllTagSelections()
+ }
+
+ private fun setSelectedAttribute(attributeName: String) {
+ if (!usesTaskAttributeStats) return
+ configureStatsButton(statStrengthButton, attributeName == Stats.STRENGTH )
+ configureStatsButton(statIntelligenceButton, attributeName == Stats.INTELLIGENCE )
+ configureStatsButton(statConstitutionButton, attributeName == Stats.CONSTITUTION )
+ configureStatsButton(statPerceptionButton, attributeName == Stats.PERCEPTION )
+ }
+
+ private fun configureStatsButton(button: TextView, isSelected: Boolean) {
+ button.background.setTint(if (isSelected) tintColor else ContextCompat.getColor(this, R.color.taskform_gray))
+ val textColorID = if (isSelected) R.color.white else R.color.gray_100
+ button.setTextColor(ContextCompat.getColor(this, textColorID))
+ }
+
+ private fun updateTagViewsColors() {
+ tagsWrapper.children.forEach { view ->
+ val tagView = view as? AppCompatCheckBox
+ val colorStateList = ColorStateList(
+ arrayOf(intArrayOf(-android.R.attr.state_checked), // unchecked
+ intArrayOf(android.R.attr.state_checked) // checked
+ ),
+ intArrayOf(ContextCompat.getColor(this, R.color.gray_400), tintColor)
+ )
+ tagView?.buttonTintList = colorStateList
+ }
+ }
+
+ private fun saveTask() {
+ var thisTask = task
+ if (thisTask == null) {
+ thisTask = Task()
+ thisTask.type = taskType
+ }
+ thisTask.text = textEditText.text.toString()
+ thisTask.notes = notesEditText.text.toString()
+ thisTask.priority = taskDifficultyButtons.selectedDifficulty
+ if (taskType == Task.TYPE_HABIT) {
+ thisTask.up = habitScoringButtons.isPositive
+ thisTask.down = habitScoringButtons.isNegative
+ thisTask.frequency = habitResetStreakButtons.selectedResetOption.value
+ if (habitAdjustPositiveStreakView.text.isNotEmpty()) thisTask.counterUp = habitAdjustPositiveStreakView.text.toString().toInt()
+ if (habitAdjustNegativeStreakView.text.isNotEmpty()) thisTask.counterDown = habitAdjustNegativeStreakView.text.toString().toInt()
+ }
+
+ thisTask.tags = RealmList()
+ tagsWrapper.forEachIndexed { index, view ->
+ val tagView = view as? CheckBox
+ if (tagView?.isChecked == true) {
+ thisTask.tags?.add(tags[index])
+ }
+ }
+
+ if (isCreating) {
+ taskRepository.createTaskInBackground(thisTask)
+ } else {
+ taskRepository.updateTaskInBackground(thisTask)
+ }
+ dismissKeyboard()
+ finish()
+ }
+
+ private fun deleteTask() {
+ task?.id?.let { taskRepository.deleteTask(it).subscribe(Consumer { }, RxErrorHandler.handleEmptyError()) }
+ dismissKeyboard()
+ finish()
+ }
+
+ private fun dismissKeyboard() {
+ val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager
+ val currentFocus = currentFocus
+ if (currentFocus != null) {
+ imm?.hideSoftInputFromWindow(currentFocus.windowToken, 0)
+ }
+ }
+
+ companion object {
+ const val TASK_ID_KEY = "taskId"
+ const val TASK_TYPE_KEY = "type"
+ const val SHOW_TAG_SELECTION = "show_tag_selection"
+
+ // in order to disable the event handler in MainActivity
+ const val SET_IGNORE_FLAG = "ignoreFlag"
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
index d1e38c228..ab63696b5 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.kt
@@ -17,6 +17,7 @@ import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.helpers.TaskFilterHelper
import com.habitrpg.android.habitica.models.tasks.Task
import com.habitrpg.android.habitica.ui.activities.OldTaskFormActivity
+import com.habitrpg.android.habitica.ui.activities.TaskFormActivity
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
import com.habitrpg.android.habitica.ui.views.tasks.TaskFilterDialog
import io.reactivex.functions.Consumer
@@ -293,7 +294,7 @@ class TasksFragment : BaseMainFragment() {
bundle.putBoolean(OldTaskFormActivity.ALLOCATION_MODE_KEY, allocationMode)
bundle.putBoolean(OldTaskFormActivity.SAVE_TO_DB, true)
- val intent = Intent(activity, OldTaskFormActivity::class.java)
+ val intent = Intent(activity, TaskFormActivity::class.java)
intent.putExtras(bundle)
intent.flags = Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
if (this.isAdded) {
@@ -317,7 +318,7 @@ class TasksFragment : BaseMainFragment() {
bundle.putBoolean(OldTaskFormActivity.ALLOCATION_MODE_KEY, allocationMode)
bundle.putBoolean(OldTaskFormActivity.SAVE_TO_DB, true)
- val intent = Intent(activity, OldTaskFormActivity::class.java)
+ val intent = Intent(activity, TaskFormActivity::class.java)
intent.putExtras(bundle)
this.displayingTaskForm = true
if (isAdded) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaIconsHelper.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaIconsHelper.java
index 2d8455e63..2584d9526 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaIconsHelper.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaIconsHelper.java
@@ -706,4 +706,34 @@ public class HabiticaIconsHelper {
return imageOfBuffIcon;
}
+
+ public static Bitmap imageOfTaskDifficultyStars(int taskTintColor, float difficulty, boolean isActive) {
+ int size = scaleSize(36);
+ Bitmap imageOfTaskDifficultyStars = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(imageOfTaskDifficultyStars);
+ canvas.scale(displayDensity, displayDensity);
+ HabiticaIcons.drawTaskDifficultyStars(canvas, taskTintColor, difficulty, isActive);
+
+ return imageOfTaskDifficultyStars;
+ }
+
+ public static Bitmap imageOfHabitControlPlus(int taskTintColor, boolean isActive) {
+ int size = scaleSize(34);
+ Bitmap imageOfHabitControlPlus = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(imageOfHabitControlPlus);
+ canvas.scale(displayDensity, displayDensity);
+ HabiticaIcons.drawHabitControlPlus(canvas, taskTintColor, isActive);
+
+ return imageOfHabitControlPlus;
+ }
+
+ public static Bitmap imageOfHabitControlMinus(int taskTintColor, boolean isActive) {
+ int size = scaleSize(34);
+ Bitmap imageOfHabitControlMinus = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(imageOfHabitControlMinus);
+ canvas.scale(displayDensity, displayDensity);
+ HabiticaIcons.drawHabitControlMinus(canvas, taskTintColor, isActive);
+
+ return imageOfHabitControlMinus;
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitResetStreakButtons.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitResetStreakButtons.kt
new file mode 100644
index 000000000..6b0db3878
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitResetStreakButtons.kt
@@ -0,0 +1,65 @@
+package com.habitrpg.android.habitica.ui.views.tasks.form
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.View
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.extensions.dpToPx
+import com.habitrpg.android.habitica.models.tasks.HabitResetOption
+
+class HabitResetStreakButtons @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+
+ var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
+
+ var selectedResetOption: HabitResetOption = HabitResetOption.DAILY
+ set(value) {
+ field = value
+ removeAllViews()
+ addAllButtons()
+ }
+
+ init {
+ addAllButtons()
+ }
+
+ private fun addAllButtons() {
+ val lastResetOption = HabitResetOption.values().last()
+ val margin = 16.dpToPx(context)
+ val height = 28.dpToPx(context)
+ for (resetOption in HabitResetOption.values()) {
+ val button = createButton(resetOption)
+ val layoutParams = LinearLayout.LayoutParams(0, height)
+ layoutParams.weight = 1f
+ if (resetOption != lastResetOption) {
+ layoutParams.marginEnd = margin
+ }
+ button.textAlignment = View.TEXT_ALIGNMENT_GRAVITY
+ button.gravity = Gravity.CENTER
+ button.layoutParams = layoutParams
+ addView(button)
+ }
+ }
+
+ private fun createButton(resetOption: HabitResetOption): TextView {
+ val button = TextView(context)
+ button.text = context.getString(resetOption.nameRes)
+ button.background = ContextCompat.getDrawable(context, R.drawable.layout_rounded_bg_white)
+ if (selectedResetOption == resetOption) {
+ button.background.setTint(tintColor)
+ button.setTextColor(ContextCompat.getColor(context, R.color.white))
+ } else {
+ button.background.setTint(ContextCompat.getColor(context, R.color.taskform_gray))
+ button.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
+ }
+ button.setOnClickListener {
+ selectedResetOption = resetOption
+ }
+ return button
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitScoringButtonsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitScoringButtonsView.kt
new file mode 100644
index 000000000..74249bf85
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/HabitScoringButtonsView.kt
@@ -0,0 +1,69 @@
+package com.habitrpg.android.habitica.ui.views.tasks.form
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.extensions.asDrawable
+import com.habitrpg.android.habitica.ui.helpers.bindView
+import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
+
+class HabitScoringButtonsView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+
+ private val positiveVew: ViewGroup by bindView(R.id.positive_view)
+ private val negativeView: ViewGroup by bindView(R.id.negative_view)
+ private val positiveImageView: ImageView by bindView(R.id.positive_image_view)
+ private val negativeImageView: ImageView by bindView(R.id.negative_image_view)
+ private val positiveTextView: TextView by bindView(R.id.positive_text_view)
+ private val negativeTextView: TextView by bindView(R.id.negative_text_view)
+
+
+ var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
+
+ var isPositive = true
+ set(value) {
+ field = value
+ positiveImageView.setImageDrawable(HabiticaIconsHelper.imageOfHabitControlPlus(tintColor, value).asDrawable(resources))
+ if (value) {
+ positiveTextView.setTextColor(tintColor)
+ } else {
+ positiveTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
+ }
+ }
+
+ var isNegative = true
+ set(value) {
+ field = value
+ negativeImageView.setImageDrawable(HabiticaIconsHelper.imageOfHabitControlMinus(tintColor, value).asDrawable(resources))
+ if (value) {
+ negativeTextView.setTextColor(tintColor)
+ } else {
+ negativeTextView.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
+ }
+ }
+
+ init {
+ View.inflate(context, R.layout.task_form_habit_scoring, this)
+ gravity = Gravity.CENTER
+
+ positiveVew.setOnClickListener {
+ isPositive = !isPositive
+ }
+ negativeView.setOnClickListener {
+ isNegative = !isNegative
+ }
+
+ isPositive = true
+ isNegative = true
+ }
+
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskDifficultyButtons.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskDifficultyButtons.kt
new file mode 100644
index 000000000..31f2980d5
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskDifficultyButtons.kt
@@ -0,0 +1,70 @@
+package com.habitrpg.android.habitica.ui.views.tasks.form
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.util.AttributeSet
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.Space
+import android.widget.TextView
+import androidx.core.content.ContextCompat
+import androidx.core.view.children
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.extensions.asDrawable
+import com.habitrpg.android.habitica.extensions.inflate
+import com.habitrpg.android.habitica.models.tasks.TaskDifficulty
+import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
+
+class TaskDifficultyButtons @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : LinearLayout(context, attrs, defStyleAttr) {
+
+ var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
+ var selectedDifficulty: Float = 1f
+ set(value) {
+ field = value
+ removeAllViews()
+ addAllButtons()
+ }
+
+ init {
+ addAllButtons()
+ }
+
+ private fun addAllButtons() {
+ val lastDifficulty = TaskDifficulty.values().last()
+ for (difficulty in TaskDifficulty.values()) {
+ val button = createButton(difficulty)
+ addView(button)
+ if (difficulty != lastDifficulty) {
+ val space = Space(context)
+ val layoutParams = LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT)
+ layoutParams.weight = 1f
+ space.layoutParams = layoutParams
+ addView(space)
+ }
+ }
+ }
+
+ private fun createButton(difficulty: TaskDifficulty): View {
+ val view = inflate(R.layout.task_form_task_difficulty, false)
+ val isActive = selectedDifficulty == difficulty.value
+ var difficultyColor = ContextCompat.getColor(context, R.color.white)
+ if (isActive) {
+ view.findViewById(R.id.image_view).background.setTint(tintColor)
+ view.findViewById(R.id.text_view).setTextColor(tintColor)
+ } else {
+ view.findViewById(R.id.image_view).background.setTint(ContextCompat.getColor(context, R.color.taskform_gray))
+ view.findViewById(R.id.text_view).setTextColor(ContextCompat.getColor(context, R.color.gray_100))
+ difficultyColor = ContextCompat.getColor(context, R.color.gray_400)
+ }
+ val drawable = HabiticaIconsHelper.imageOfTaskDifficultyStars(difficultyColor, difficulty.value, true).asDrawable(resources)
+ view.findViewById(R.id.image_view).setImageDrawable(drawable)
+ view.findViewById(R.id.text_view).text = context.getText(difficulty.nameRes)
+ view.setOnClickListener {
+ selectedDifficulty = difficulty.value
+ }
+ return view
+ }
+}
\ No newline at end of file