mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-22 05:38:55 +00:00
Continue implementing new task form
This commit is contained in:
parent
cca994fad5
commit
80ef5e1bdb
21 changed files with 1016 additions and 47 deletions
|
|
@ -150,7 +150,7 @@ android {
|
|||
buildConfigField "String", "STORE", "\"google\""
|
||||
multiDexEnabled true
|
||||
|
||||
versionCode 2080
|
||||
versionCode 2081
|
||||
versionName "1.8.1"
|
||||
}
|
||||
|
||||
|
|
|
|||
7
Habitica/res/anim/rotate_45_degrees.xml
Normal file
7
Habitica/res/anim/rotate_45_degrees.xml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<rotate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fromDegrees="0"
|
||||
android:toDegrees="45"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%" />
|
||||
5
Habitica/res/drawable/plus_taskform.xml
Normal file
5
Habitica/res/drawable/plus_taskform.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
||||
16
Habitica/res/drawable/task_form_control_bg.xml
Normal file
16
Habitica/res/drawable/task_form_control_bg.xml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/gray_500" />
|
||||
<corners android:radius="4dp" android:topLeftRadius="8dp" android:topRightRadius="8dp" />
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item android:bottom="4dp">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="@color/gray_700" />
|
||||
<corners android:topLeftRadius="4dp" android:topRightRadius="4dp" android:bottomLeftRadius="2dp" android:bottomRightRadius="2dp" />
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
@ -75,6 +75,17 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/checklist_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/checklist"
|
||||
style="@style/TaskFormSectionheader"/>
|
||||
<com.habitrpg.android.habitica.ui.views.tasks.form.ChecklistContainer
|
||||
android:id="@+id/checklist_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/task_difficulty_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/difficulty"
|
||||
|
|
@ -93,6 +104,16 @@
|
|||
android:id="@+id/habit_reset_streak_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/scheduling_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/scheduling"
|
||||
style="@style/TaskFormSectionheader"/>
|
||||
<com.habitrpg.android.habitica.ui.views.tasks.form.TaskSchedulingControls
|
||||
android:id="@+id/scheduling_controls"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/adjust_streak_title"
|
||||
android:layout_width="match_parent"
|
||||
|
|
@ -131,6 +152,18 @@
|
|||
android:inputType="number"/>
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/reminders_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/reminders"
|
||||
style="@style/TaskFormSectionheader"/>
|
||||
<com.habitrpg.android.habitica.ui.views.tasks.form.ReminderContainer
|
||||
android:id="@+id/reminders_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/stat_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
31
Habitica/res/layout/task_form_checklist_item.xml
Normal file
31
Habitica/res/layout/task_form_checklist_item.xml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/layout_rounded_bg_task_form"
|
||||
android:minHeight="38dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingTop="@dimen/spacing_small"
|
||||
android:paddingBottom="@dimen/spacing_small"
|
||||
android:layout_marginBottom="@dimen/spacing_medium"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
<ImageButton
|
||||
android:id="@+id/button"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@color/transparent"
|
||||
android:src="@drawable/plus_taskform"
|
||||
android:scaleType="center"
|
||||
android:layout_marginEnd="@dimen/spacing_large"/>
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/transparent"
|
||||
android:hint="@string/new_checklist_item"
|
||||
android:textSize="14sp"/>
|
||||
</merge>
|
||||
31
Habitica/res/layout/task_form_reminder_item.xml
Normal file
31
Habitica/res/layout/task_form_reminder_item.xml
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/layout_rounded_bg_task_form"
|
||||
android:minHeight="38dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:paddingTop="@dimen/spacing_small"
|
||||
android:paddingBottom="@dimen/spacing_small"
|
||||
android:layout_marginBottom="@dimen/spacing_medium"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
<ImageButton
|
||||
android:id="@+id/button"
|
||||
android:layout_width="38dp"
|
||||
android:layout_height="30dp"
|
||||
android:background="@color/transparent"
|
||||
android:src="@drawable/plus_taskform"
|
||||
android:scaleType="center"
|
||||
android:layout_marginEnd="@dimen/spacing_large"/>
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/transparent"
|
||||
android:text="@string/new_reminder"
|
||||
android:textSize="14sp"/>
|
||||
</merge>
|
||||
149
Habitica/res/layout/task_form_task_scheduling.xml
Normal file
149
Habitica/res/layout/task_form_task_scheduling.xml
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/start_date_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/task_form_control_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/spacing_large"
|
||||
android:paddingTop="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_large"
|
||||
android:paddingBottom="@dimen/spacing_medium"
|
||||
android:layout_marginBottom="@dimen/spacing_large">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/start_date_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/start_date"
|
||||
android:textColor="@color/gray_300"
|
||||
android:textSize="12sp" />
|
||||
<TextView
|
||||
android:id="@+id/start_date_textview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
tools:text="Thu, November 2, 2017"
|
||||
android:drawableEnd="@drawable/ic_arrow_drop_down_80000000_24dp"/>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/repeats_every_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/task_form_control_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/spacing_large"
|
||||
android:paddingTop="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_large"
|
||||
android:paddingBottom="@dimen/spacing_medium"
|
||||
android:layout_marginBottom="@dimen/spacing_large"
|
||||
android:layout_marginRight="@dimen/spacing_medium">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/repeats"
|
||||
android:textColor="@color/gray_300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/repeats_every_spinner"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/task_form_control_bg"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="@dimen/spacing_large"
|
||||
android:paddingTop="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_large"
|
||||
android:paddingBottom="@dimen/spacing_medium"
|
||||
android:layout_marginBottom="@dimen/spacing_large"
|
||||
android:layout_marginLeft="@dimen/spacing_medium">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/every"
|
||||
android:textColor="@color/gray_300"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatEditText
|
||||
android:id="@+id/repeats_every_edittext"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:textSize="16sp"
|
||||
tools:text="1"
|
||||
android:inputType="number"
|
||||
android:background="@color/transparent"
|
||||
android:textColor="@color/gray_100"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repeats_every_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="@string/days"
|
||||
android:textColor="@color/gray_300"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/weekly_repeat_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/monthly_repeat_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/monthly_repeat_days"
|
||||
style="@style/TaskFormToggle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="28dp"
|
||||
android:text="@string/repeatables_frequency_day_of_month"
|
||||
android:layout_marginRight="@dimen/spacing_medium"/>
|
||||
<TextView
|
||||
android:id="@+id/monthly_repeat_weeks"
|
||||
style="@style/TaskFormToggle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="28dp"
|
||||
android:text="@string/repeatables_frequency_day_of_week"
|
||||
android:layout_marginLeft="@dimen/spacing_medium"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/summary_textview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/gray_300"
|
||||
android:textSize="12sp" />
|
||||
</merge>
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
<string name="mana_price_button">%d MP</string>
|
||||
<string name="used_skill">You used %1$s for %2$d mana.</string>
|
||||
<string name="used_skill_without_mana">You used %1$s.</string>
|
||||
<string name="new_checklist_item">new checklist item</string>
|
||||
<string name="new_checklist_item">New checklist entry</string>
|
||||
<string name="add_checklist_item">Add</string>
|
||||
|
||||
<string name="reminder_title">Remember to check off your tasks</string>
|
||||
|
|
@ -505,7 +505,7 @@
|
|||
<string name="monthly_gem_cap">Monthly gem cap</string>
|
||||
<string name="inactive">Inactive</string>
|
||||
<string name="one_month">1 Month</string>
|
||||
<string name="months">%d Months</string>
|
||||
<string name="x_months">%d Months</string>
|
||||
<string name="month">month</string>
|
||||
<string name="three_months">3 months</string>
|
||||
<string name="six_months">6 months</string>
|
||||
|
|
@ -876,4 +876,14 @@
|
|||
<string name="assigned_stat">Assigned Stat</string>
|
||||
<string name="monthly">Monthly</string>
|
||||
<string name="weekly">Weekly</string>
|
||||
<string name="repeats">Repeats</string>
|
||||
<string name="every">Every</string>
|
||||
<string name="scheduling">Scheduling</string>
|
||||
<string name="days">Days</string>
|
||||
<string name="weeks">Weeks</string>
|
||||
<string name="months">Months</string>
|
||||
<string name="years">Years</string>
|
||||
<string name="checklist_text">Checklist Text</string>
|
||||
<string name="new_reminder">New reminder</string>
|
||||
<string name="streak">Streak</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -518,5 +518,11 @@
|
|||
<item name="android:height">28dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TaskFormWeekdayButton">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:textAlignment">gravity</item>
|
||||
</style>
|
||||
|
||||
<color name="taskform_gray">#99edecee</color>
|
||||
</resources>
|
||||
|
|
@ -81,10 +81,10 @@ open class Task : RealmObject, Parcelable {
|
|||
private var weeksOfMonthString: String? = null
|
||||
|
||||
@Ignore
|
||||
private var daysOfMonth: MutableList<Int>? = null
|
||||
private var daysOfMonth: List<Int>? = null
|
||||
|
||||
@Ignore
|
||||
private var weeksOfMonth: MutableList<Int>? = null
|
||||
private var weeksOfMonth: List<Int>? = null
|
||||
|
||||
val completedChecklistCount: Int
|
||||
get() = checklist?.count { it.completed } ?: 0
|
||||
|
|
@ -306,56 +306,54 @@ open class Task : RealmObject, Parcelable {
|
|||
}
|
||||
|
||||
|
||||
fun setWeeksOfMonth(weeksOfMonth: MutableList<Int>) {
|
||||
fun setWeeksOfMonth(weeksOfMonth: List<Int>?) {
|
||||
this.weeksOfMonth = weeksOfMonth
|
||||
this.weeksOfMonthString = this.weeksOfMonth?.toString()
|
||||
}
|
||||
|
||||
fun getWeeksOfMonth(): List<Int>? {
|
||||
if (weeksOfMonth == null) {
|
||||
weeksOfMonth = ArrayList()
|
||||
val weeksOfMonth = mutableListOf<Int>()
|
||||
if (weeksOfMonthString != null) {
|
||||
try {
|
||||
val obj = JSONArray(weeksOfMonthString)
|
||||
var i = 0
|
||||
while (i < obj.length()) {
|
||||
weeksOfMonth?.add(obj.getInt(i))
|
||||
weeksOfMonth.add(obj.getInt(i))
|
||||
i += 1
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} else {
|
||||
weeksOfMonth = ArrayList()
|
||||
}
|
||||
this.weeksOfMonth = weeksOfMonth.toList()
|
||||
}
|
||||
return weeksOfMonth
|
||||
}
|
||||
|
||||
fun setDaysOfMonth(daysOfMonth: MutableList<Int>) {
|
||||
fun setDaysOfMonth(daysOfMonth: List<Int>?) {
|
||||
this.daysOfMonth = daysOfMonth
|
||||
this.daysOfMonthString = daysOfMonth.toString()
|
||||
}
|
||||
|
||||
fun getDaysOfMonth(): List<Int>? {
|
||||
if (daysOfMonth == null) {
|
||||
daysOfMonth = ArrayList()
|
||||
val daysOfMonth = mutableListOf<Int>()
|
||||
if (daysOfMonthString != null) {
|
||||
try {
|
||||
val obj = JSONArray(daysOfMonthString)
|
||||
var i = 0
|
||||
while (i < obj.length()) {
|
||||
daysOfMonth?.add(obj.getInt(i))
|
||||
daysOfMonth.add(obj.getInt(i))
|
||||
i += 1
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
} else {
|
||||
daysOfMonth = ArrayList()
|
||||
}
|
||||
this.daysOfMonth = daysOfMonth
|
||||
}
|
||||
|
||||
return daysOfMonth
|
||||
|
|
@ -381,6 +379,7 @@ open class Task : RealmObject, Parcelable {
|
|||
const val FREQUENCY_WEEKLY = "weekly"
|
||||
const val FREQUENCY_DAILY = "daily"
|
||||
const val FREQUENCY_MONTHLY = "monthly"
|
||||
const val FREQUENCY_YEARLY = "yearly"
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<Task> = object : Parcelable.Creator<Task> {
|
||||
|
|
|
|||
|
|
@ -964,13 +964,8 @@ class OldTaskFormActivity : BaseActivity() {
|
|||
val dayOfTheWeek = sharedPreferences.getString("FirstDayOfTheWeek",
|
||||
Integer.toString(Calendar.getInstance().firstDayOfWeek))
|
||||
val firstDayOfTheWeekHelper = FirstDayOfTheWeekHelper.newInstance(Integer.parseInt(dayOfTheWeek ?: "0"))
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT_WATCH) {
|
||||
@Suppress("DEPRECATION")
|
||||
datePickerDialog.datePicker.calendarView.firstDayOfWeek = firstDayOfTheWeekHelper.firstDayOfTheWeek
|
||||
} else {
|
||||
datePickerDialog.datePicker.firstDayOfWeek = firstDayOfTheWeekHelper
|
||||
datePickerDialog.datePicker.firstDayOfWeek = firstDayOfTheWeekHelper
|
||||
.firstDayOfTheWeek
|
||||
}
|
||||
|
||||
this.datePickerDialog.setButton(DialogInterface.BUTTON_NEUTRAL, resources.getString(R.string.today)) { _, _ -> setCalendar(Calendar.getInstance().time) }
|
||||
updateDateText()
|
||||
|
|
|
|||
|
|
@ -23,9 +23,6 @@ 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
|
||||
|
|
@ -37,7 +34,9 @@ import androidx.core.view.children
|
|||
import androidx.core.view.forEach
|
||||
import androidx.core.view.forEachIndexed
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.ui.views.tasks.form.*
|
||||
import io.realm.RealmList
|
||||
import java.util.*
|
||||
|
||||
|
||||
class TaskFormActivity : BaseActivity() {
|
||||
|
|
@ -54,13 +53,20 @@ class TaskFormActivity : BaseActivity() {
|
|||
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 checklistTitleView: TextView by bindView(R.id.checklist_title)
|
||||
private val checklistContainer: ChecklistContainer by bindView(R.id.checklist_container)
|
||||
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 taskSchedulingTitleView: TextView by bindView(R.id.scheduling_title)
|
||||
private val taskSchedulingControls: TaskSchedulingControls by bindView(R.id.scheduling_controls)
|
||||
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 remindersTitleView: TextView by bindView(R.id.reminders_title)
|
||||
private val remindersContainer: ReminderContainer by bindView(R.id.reminders_container)
|
||||
|
||||
private val taskDifficultyTitleView: TextView by bindView(R.id.task_difficulty_title)
|
||||
private val taskDifficultyButtons: TaskDifficultyButtons by bindView(R.id.task_difficulty_buttons)
|
||||
|
||||
private val statWrapper: ViewGroup by bindView(R.id.stat_wrapper)
|
||||
|
|
@ -115,7 +121,7 @@ class TaskFormActivity : BaseActivity() {
|
|||
val taskId = bundle.getString(OldTaskFormActivity.TASK_ID_KEY)
|
||||
if (taskId != null) {
|
||||
isCreating = false
|
||||
compositeSubscription.add(taskRepository.getUnmanagedTask(taskId).subscribe(Consumer {
|
||||
compositeSubscription.add(taskRepository.getUnmanagedTask(taskId).firstElement().subscribe(Consumer {
|
||||
task = it
|
||||
//tintColor = ContextCompat.getColor(this, it.mediumTaskColor)
|
||||
fillForm(it)
|
||||
|
|
@ -164,11 +170,32 @@ class TaskFormActivity : BaseActivity() {
|
|||
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
|
||||
val habitDailyVisibility = if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_HABIT) View.VISIBLE else View.GONE
|
||||
adjustStreakTitleView.visibility = habitDailyVisibility
|
||||
adjustStreakWrapper.visibility = habitDailyVisibility
|
||||
if (taskType == Task.TYPE_HABIT) {
|
||||
habitAdjustPositiveStreakView.hint = getString(R.string.positive_habit_form)
|
||||
} else {
|
||||
habitAdjustPositiveStreakView.hint = getString(R.string.streak)
|
||||
}
|
||||
|
||||
val todoDailyViewsVisibility = if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) View.VISIBLE else View.GONE
|
||||
|
||||
checklistTitleView.visibility = todoDailyViewsVisibility
|
||||
checklistContainer.visibility = todoDailyViewsVisibility
|
||||
|
||||
remindersTitleView.visibility = todoDailyViewsVisibility
|
||||
remindersContainer.visibility = todoDailyViewsVisibility
|
||||
|
||||
val rewardHideViews = if (taskType == Task.TYPE_REWARD) View.GONE else View.VISIBLE
|
||||
taskDifficultyTitleView.visibility = rewardHideViews
|
||||
taskDifficultyButtons.visibility = rewardHideViews
|
||||
|
||||
taskSchedulingTitleView.visibility = todoDailyViewsVisibility
|
||||
taskSchedulingControls.visibility = todoDailyViewsVisibility
|
||||
taskSchedulingControls.taskType = taskType
|
||||
|
||||
statWrapper.visibility = if (usesTaskAttributeStats) View.VISIBLE else View.GONE
|
||||
if (isCreating) {
|
||||
|
|
@ -201,12 +228,28 @@ class TaskFormActivity : BaseActivity() {
|
|||
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())
|
||||
when (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.TYPE_DAILY -> {
|
||||
taskSchedulingControls.startDate = task.startDate ?: Date()
|
||||
taskSchedulingControls.frequency = task.frequency ?: Task.FREQUENCY_DAILY
|
||||
taskSchedulingControls.everyX = task.everyX ?: 1
|
||||
task.repeat?.let { taskSchedulingControls.weeklyRepeat = it }
|
||||
taskSchedulingControls.daysOfMonth = task.getDaysOfMonth()
|
||||
taskSchedulingControls.weeksOfMonth = task.getWeeksOfMonth()
|
||||
habitAdjustPositiveStreakView.setText((task.streak ?: 0).toString())
|
||||
}
|
||||
Task.TYPE_TODO -> taskSchedulingControls.dueDate = task.dueDate
|
||||
}
|
||||
if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) {
|
||||
task.checklist?.let { checklistContainer.checklistItems = it }
|
||||
task.reminders?.let { remindersContainer.reminders = it }
|
||||
}
|
||||
task.attribute?.let { setSelectedAttribute(it) }
|
||||
setAllTagSelections()
|
||||
|
|
@ -254,8 +297,22 @@ class TaskFormActivity : BaseActivity() {
|
|||
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()
|
||||
} else if (taskType == Task.TYPE_DAILY) {
|
||||
thisTask.startDate = taskSchedulingControls.startDate
|
||||
thisTask.everyX = taskSchedulingControls.everyX
|
||||
thisTask.frequency = taskSchedulingControls.frequency
|
||||
thisTask.repeat = taskSchedulingControls.weeklyRepeat
|
||||
thisTask.setDaysOfMonth(taskSchedulingControls.daysOfMonth)
|
||||
thisTask.setWeeksOfMonth(taskSchedulingControls.weeksOfMonth)
|
||||
if (habitAdjustPositiveStreakView.text.isNotEmpty()) thisTask.streak = habitAdjustPositiveStreakView.text.toString().toInt()
|
||||
} else if (taskType == Task.TYPE_TODO) {
|
||||
thisTask.dueDate = taskSchedulingControls.dueDate
|
||||
}
|
||||
|
||||
if (taskType == Task.TYPE_DAILY || taskType == Task.TYPE_TODO) {
|
||||
thisTask.checklist = checklistContainer.checklistItems
|
||||
thisTask.reminders = remindersContainer.reminders
|
||||
}
|
||||
thisTask.tags = RealmList()
|
||||
tagsWrapper.forEachIndexed { index, view ->
|
||||
val tagView = view as? CheckBox
|
||||
|
|
|
|||
|
|
@ -286,12 +286,8 @@ class TasksFragment : BaseMainFragment() {
|
|||
return
|
||||
}
|
||||
|
||||
val allocationMode = user?.preferences?.hasTaskBasedAllocation() ?: false
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putString(OldTaskFormActivity.TASK_TYPE_KEY, type)
|
||||
bundle.putString(OldTaskFormActivity.USER_ID_KEY, if (this.user != null) this.user?.id else null)
|
||||
bundle.putBoolean(OldTaskFormActivity.ALLOCATION_MODE_KEY, allocationMode)
|
||||
bundle.putBoolean(OldTaskFormActivity.SAVE_TO_DB, true)
|
||||
|
||||
val intent = Intent(activity, TaskFormActivity::class.java)
|
||||
|
|
@ -309,14 +305,9 @@ class TasksFragment : BaseMainFragment() {
|
|||
return
|
||||
}
|
||||
|
||||
val allocationMode = user?.preferences?.hasTaskBasedAllocation() ?: false
|
||||
|
||||
val bundle = Bundle()
|
||||
bundle.putString(OldTaskFormActivity.TASK_TYPE_KEY, event.Task.type)
|
||||
bundle.putString(OldTaskFormActivity.TASK_ID_KEY, event.Task.id)
|
||||
bundle.putString(OldTaskFormActivity.USER_ID_KEY, if (this.user != null) this.user?.id else null)
|
||||
bundle.putBoolean(OldTaskFormActivity.ALLOCATION_MODE_KEY, allocationMode)
|
||||
bundle.putBoolean(OldTaskFormActivity.SAVE_TO_DB, true)
|
||||
|
||||
val intent = Intent(activity, TaskFormActivity::class.java)
|
||||
intent.putExtras(bundle)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
package com.habitrpg.android.habitica.ui.views.tasks.form
|
||||
|
||||
import android.animation.LayoutTransition
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.updateMargins
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.models.tasks.ChecklistItem
|
||||
import io.realm.RealmList
|
||||
|
||||
class ChecklistContainer @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
var checklistItems: RealmList<ChecklistItem>
|
||||
get() {
|
||||
val list = RealmList<ChecklistItem>()
|
||||
for (child in children) {
|
||||
val view = child as? ChecklistItemFormView ?: continue
|
||||
if (view.item.text?.isNotEmpty() == true) {
|
||||
list.add(view.item)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
set(value) {
|
||||
val unAnimatedTransitions = LayoutTransition()
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.APPEARING)
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.CHANGING)
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.DISAPPEARING)
|
||||
layoutTransition = unAnimatedTransitions
|
||||
if (childCount > 1) {
|
||||
for (child in children.take(childCount - 1)) {
|
||||
removeView(child)
|
||||
}
|
||||
}
|
||||
for (item in value) {
|
||||
addChecklistViewAt(childCount-1, item)
|
||||
}
|
||||
val animatedTransitions = LayoutTransition()
|
||||
layoutTransition = animatedTransitions
|
||||
}
|
||||
|
||||
init {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
|
||||
addChecklistViewAt(0)
|
||||
}
|
||||
|
||||
private fun addChecklistViewAt(index: Int, item: ChecklistItem? = null) {
|
||||
val view = ChecklistItemFormView(context)
|
||||
item?.let {
|
||||
view.item = it
|
||||
view.isAddButton = false
|
||||
}
|
||||
view.textChangedListener = {
|
||||
if (isLastChild(view)) {
|
||||
addChecklistViewAt(-1)
|
||||
view.animDuration = 300
|
||||
view.isAddButton = false
|
||||
} else if (shouldBecomeNewAddButton(view)) {
|
||||
removeViewAt(childCount-1)
|
||||
view.animDuration = 300
|
||||
view.isAddButton = true
|
||||
}
|
||||
}
|
||||
val indexToUse = if (index < 0) {
|
||||
childCount - index
|
||||
} else {
|
||||
index
|
||||
}
|
||||
if (childCount <= indexToUse) {
|
||||
addView(view)
|
||||
view.isAddButton = true
|
||||
} else {
|
||||
addView(view, indexToUse)
|
||||
}
|
||||
val layoutParams = view.layoutParams as? LinearLayout.LayoutParams
|
||||
layoutParams?.updateMargins(bottom = 8.dpToPx(context))
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun shouldBecomeNewAddButton(view: ChecklistItemFormView): Boolean {
|
||||
if (childCount > 2 && view.item.text?.isEmpty() != false && children.indexOf(view) == childCount-2) {
|
||||
val lastView = (getChildAt(childCount-1) as? ChecklistItemFormView)
|
||||
if (lastView != null && lastView.item.text?.isEmpty() != false) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isLastChild(view: View): Boolean {
|
||||
return children.lastOrNull() == view
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package com.habitrpg.android.habitica.ui.views.tasks.form
|
||||
|
||||
import android.animation.ObjectAnimator
|
||||
import android.content.Context
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.models.tasks.ChecklistItem
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.RotateAnimation
|
||||
|
||||
|
||||
|
||||
|
||||
class ChecklistItemFormView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr), TextWatcher {
|
||||
|
||||
|
||||
private val button: ImageButton by bindView(R.id.button)
|
||||
private val editText: EditText by bindView(R.id.edit_text)
|
||||
|
||||
var item: ChecklistItem = ChecklistItem()
|
||||
set(value) {
|
||||
field = value
|
||||
editText.setText(item.text)
|
||||
}
|
||||
|
||||
var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
|
||||
var textChangedListener: ((String) -> Unit)? = null
|
||||
var animDuration = 0L
|
||||
var isAddButton: Boolean = true
|
||||
set(value) {
|
||||
field = value
|
||||
editText.hint = context.getString(if (value) R.string.new_checklist_item else R.string.checklist_text)
|
||||
if (value) {
|
||||
val rotate = RotateAnimation(135f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
|
||||
rotate.duration = animDuration
|
||||
rotate.interpolator = LinearInterpolator()
|
||||
rotate.fillAfter = true
|
||||
button.startAnimation(rotate)
|
||||
} else {
|
||||
val rotate = RotateAnimation(0f, 135f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
|
||||
rotate.duration = animDuration
|
||||
rotate.interpolator = LinearInterpolator()
|
||||
rotate.fillAfter = true
|
||||
button.startAnimation(rotate)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
minimumHeight = 38.dpToPx(context)
|
||||
inflate(R.layout.task_form_checklist_item, true)
|
||||
background = context.getDrawable(R.drawable.layout_rounded_bg_task_form)
|
||||
background.mutate().setTint(ContextCompat.getColor(context, R.color.taskform_gray))
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
button.setOnClickListener {
|
||||
if (!isAddButton) {
|
||||
(parent as? ViewGroup)?.removeView(this)
|
||||
}
|
||||
}
|
||||
button.drawable.mutate().setTint(tintColor)
|
||||
|
||||
editText.addTextChangedListener(this)
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable?) {
|
||||
}
|
||||
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
|
||||
}
|
||||
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
item.text = s.toString()
|
||||
textChangedListener?.let { it(s.toString()) }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -64,6 +64,4 @@ class HabitScoringButtonsView @JvmOverloads constructor(
|
|||
isPositive = true
|
||||
isNegative = true
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
package com.habitrpg.android.habitica.ui.views.tasks.form
|
||||
|
||||
import android.animation.LayoutTransition
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.updateMargins
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.models.tasks.ChecklistItem
|
||||
import com.habitrpg.android.habitica.models.tasks.RemindersItem
|
||||
import io.realm.RealmList
|
||||
|
||||
class ReminderContainer @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr) {
|
||||
var reminders: RealmList<RemindersItem>
|
||||
get() {
|
||||
val list = RealmList<RemindersItem>()
|
||||
for (child in children) {
|
||||
val view = child as? ReminderItemFormView ?: continue
|
||||
if (view.item.time != null) {
|
||||
list.add(view.item)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
set(value) {
|
||||
val unAnimatedTransitions = LayoutTransition()
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.APPEARING)
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.CHANGING)
|
||||
unAnimatedTransitions.disableTransitionType(LayoutTransition.DISAPPEARING)
|
||||
layoutTransition = unAnimatedTransitions
|
||||
if (childCount > 1) {
|
||||
for (child in children.take(childCount - 1)) {
|
||||
removeView(child)
|
||||
}
|
||||
}
|
||||
for (item in value) {
|
||||
addReminderViewAt(childCount-1, item)
|
||||
}
|
||||
val animatedTransitions = LayoutTransition()
|
||||
layoutTransition = animatedTransitions
|
||||
}
|
||||
|
||||
init {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
|
||||
addReminderViewAt(0)
|
||||
}
|
||||
|
||||
private fun addReminderViewAt(index: Int, item: RemindersItem? = null) {
|
||||
val view = ReminderItemFormView(context)
|
||||
item?.let {
|
||||
view.item = it
|
||||
view.isAddButton = false
|
||||
}
|
||||
view.valueChangedListener = {
|
||||
if (isLastChild(view)) {
|
||||
addReminderViewAt(-1)
|
||||
view.animDuration = 300
|
||||
view.isAddButton = false
|
||||
}
|
||||
}
|
||||
val indexToUse = if (index < 0) {
|
||||
childCount - index
|
||||
} else {
|
||||
index
|
||||
}
|
||||
if (childCount <= indexToUse) {
|
||||
addView(view)
|
||||
view.isAddButton = true
|
||||
} else {
|
||||
addView(view, indexToUse)
|
||||
}
|
||||
val layoutParams = view.layoutParams as? LinearLayout.LayoutParams
|
||||
layoutParams?.updateMargins(bottom = 8.dpToPx(context))
|
||||
view.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun isLastChild(view: View): Boolean {
|
||||
return children.lastOrNull() == view
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
package com.habitrpg.android.habitica.ui.views.tasks.form
|
||||
|
||||
import android.app.DatePickerDialog
|
||||
import android.app.TimePickerDialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.util.AttributeSet
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.LinearInterpolator
|
||||
import android.view.animation.RotateAnimation
|
||||
import android.widget.ImageButton
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import android.widget.TimePicker
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.models.tasks.RemindersItem
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
import java.text.DateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
class ReminderItemFormView @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr), TimePickerDialog.OnTimeSetListener {
|
||||
|
||||
|
||||
private val button: ImageButton by bindView(R.id.button)
|
||||
private val textView: TextView by bindView(R.id.text_view)
|
||||
|
||||
private val formatter = DateFormat.getTimeInstance(DateFormat.SHORT)
|
||||
|
||||
var item: RemindersItem = RemindersItem()
|
||||
set(value) {
|
||||
field = value
|
||||
textView.text = formatter.format(item.time)
|
||||
}
|
||||
|
||||
var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
|
||||
var valueChangedListener: ((Date) -> Unit)? = null
|
||||
var animDuration = 0L
|
||||
var isAddButton: Boolean = true
|
||||
set(value) {
|
||||
field = value
|
||||
textView.text = if (value) context.getString(R.string.new_reminder) else formatter.format(item.time)
|
||||
if (value) {
|
||||
val rotate = RotateAnimation(135f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
|
||||
rotate.duration = animDuration
|
||||
rotate.interpolator = LinearInterpolator()
|
||||
rotate.fillAfter = true
|
||||
button.startAnimation(rotate)
|
||||
} else {
|
||||
val rotate = RotateAnimation(0f, 135f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f)
|
||||
rotate.duration = animDuration
|
||||
rotate.interpolator = LinearInterpolator()
|
||||
rotate.fillAfter = true
|
||||
button.startAnimation(rotate)
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
minimumHeight = 38.dpToPx(context)
|
||||
inflate(R.layout.task_form_reminder_item, true)
|
||||
background = context.getDrawable(R.drawable.layout_rounded_bg_task_form)
|
||||
background.mutate().setTint(ContextCompat.getColor(context, R.color.taskform_gray))
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
button.setOnClickListener {
|
||||
if (!isAddButton) {
|
||||
(parent as? ViewGroup)?.removeView(this)
|
||||
}
|
||||
}
|
||||
button.drawable.mutate().setTint(tintColor)
|
||||
|
||||
textView.setOnClickListener {
|
||||
val calendar = Calendar.getInstance()
|
||||
item.time?.let { calendar.time = it }
|
||||
val timePickerDialog = TimePickerDialog(context, this,
|
||||
calendar.get(Calendar.HOUR_OF_DAY),
|
||||
calendar.get(Calendar.MINUTE),
|
||||
android.text.format.DateFormat.is24HourFormat(context))
|
||||
timePickerDialog.show()
|
||||
}
|
||||
}
|
||||
override fun onTimeSet(view: TimePicker?, hourOfDay: Int, minute: Int) {
|
||||
valueChangedListener?.let {
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay)
|
||||
calendar.set(Calendar.MINUTE, minute)
|
||||
item.time = calendar.time
|
||||
textView.text = formatter.format(item.time)
|
||||
item.time?.let { date -> it(date) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,10 +52,10 @@ class TaskDifficultyButtons @JvmOverloads constructor(
|
|||
val isActive = selectedDifficulty == difficulty.value
|
||||
var difficultyColor = ContextCompat.getColor(context, R.color.white)
|
||||
if (isActive) {
|
||||
view.findViewById<ImageView>(R.id.image_view).background.setTint(tintColor)
|
||||
view.findViewById<ImageView>(R.id.image_view).background.mutate().setTint(tintColor)
|
||||
view.findViewById<TextView>(R.id.text_view).setTextColor(tintColor)
|
||||
} else {
|
||||
view.findViewById<ImageView>(R.id.image_view).background.setTint(ContextCompat.getColor(context, R.color.taskform_gray))
|
||||
view.findViewById<ImageView>(R.id.image_view).background.mutate().setTint(ContextCompat.getColor(context, R.color.taskform_gray))
|
||||
view.findViewById<TextView>(R.id.text_view).setTextColor(ContextCompat.getColor(context, R.color.gray_100))
|
||||
difficultyColor = ContextCompat.getColor(context, R.color.gray_400)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,269 @@
|
|||
package com.habitrpg.android.habitica.ui.views.tasks.form
|
||||
|
||||
import android.app.DatePickerDialog
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.extensions.dpToPx
|
||||
import com.habitrpg.android.habitica.extensions.inflate
|
||||
import com.habitrpg.android.habitica.helpers.FirstDayOfTheWeekHelper
|
||||
import com.habitrpg.android.habitica.models.tasks.Days
|
||||
import com.habitrpg.android.habitica.models.tasks.Task
|
||||
import com.habitrpg.android.habitica.ui.helpers.bindView
|
||||
import java.text.DateFormat
|
||||
import java.text.DateFormatSymbols
|
||||
import java.util.*
|
||||
|
||||
class TaskSchedulingControls @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||
) : LinearLayout(context, attrs, defStyleAttr), DatePickerDialog.OnDateSetListener {
|
||||
|
||||
var tintColor: Int = ContextCompat.getColor(context, R.color.brand_300)
|
||||
|
||||
private val startDateWrapper: ViewGroup by bindView(R.id.start_date_wrapper)
|
||||
private val startDateTitleView: TextView by bindView(R.id.start_date_title)
|
||||
private val startDateTextView: TextView by bindView(R.id.start_date_textview)
|
||||
private val repeatsEveryWrapper: ViewGroup by bindView(R.id.repeats_every_wrapper)
|
||||
private val repeatsEverySpinner: Spinner by bindView(R.id.repeats_every_spinner)
|
||||
private val repeatsEveryEdittext: AppCompatEditText by bindView(R.id.repeats_every_edittext)
|
||||
private val repeatsEveryTitleView: TextView by bindView(R.id.repeats_every_title)
|
||||
private val weeklyRepeatWrapper: ViewGroup by bindView(R.id.weekly_repeat_wrapper)
|
||||
private val monthlyRepeatWrapper: ViewGroup by bindView(R.id.monthly_repeat_wrapper)
|
||||
private val monthlyRepeatDaysButton: TextView by bindView(R.id.monthly_repeat_days)
|
||||
private val monthlyRepeatWeeksButton: TextView by bindView(R.id.monthly_repeat_weeks)
|
||||
private val summaryTextView: TextView by bindView(R.id.summary_textview)
|
||||
|
||||
private val dateFormatter = DateFormat.getDateInstance(DateFormat.MEDIUM)
|
||||
private val frequencyAdapter = ArrayAdapter.createFromResource(context,
|
||||
R.array.repeatables_frequencies, android.R.layout.simple_spinner_item)
|
||||
|
||||
var taskType = Task.TYPE_DAILY
|
||||
set(value) {
|
||||
field = value
|
||||
configureViewsForType()
|
||||
}
|
||||
var startDate = Date()
|
||||
set(value) {
|
||||
field = value
|
||||
startDateTextView.text = dateFormatter.format(value)
|
||||
startDateCalendar.time = value
|
||||
}
|
||||
private var startDateCalendar = Calendar.getInstance()
|
||||
var dueDate: Date? = null
|
||||
set(value) {
|
||||
field = value
|
||||
value?.let { startDateTextView.text = dateFormatter.format(it) }
|
||||
}
|
||||
var frequency = Task.FREQUENCY_DAILY
|
||||
set(value) {
|
||||
field = value
|
||||
repeatsEverySpinner.setSelection(when (value) {
|
||||
Task.FREQUENCY_WEEKLY -> 1
|
||||
Task.FREQUENCY_MONTHLY -> 2
|
||||
Task.FREQUENCY_YEARLY -> 3
|
||||
else -> 0
|
||||
})
|
||||
configureViewsForFrequency()
|
||||
}
|
||||
var everyX
|
||||
get() = (repeatsEveryEdittext.text ?: "1").toString().toInt()
|
||||
set(value) {
|
||||
repeatsEveryEdittext.setText(value.toString())
|
||||
}
|
||||
var weeklyRepeat: Days = Days()
|
||||
set(value) {
|
||||
field = value
|
||||
createWeeklyRepeatViews()
|
||||
}
|
||||
|
||||
var daysOfMonth: List<Int>? = null
|
||||
set(value) {
|
||||
field = value
|
||||
configureMonthlyRepeatViews()
|
||||
}
|
||||
var weeksOfMonth: List<Int>? = null
|
||||
set(value) {
|
||||
field = value
|
||||
configureMonthlyRepeatViews()
|
||||
}
|
||||
|
||||
private val weekdays: Array<String> by lazy {
|
||||
DateFormatSymbols().weekdays
|
||||
}
|
||||
private val weekdayOrder: List<Int> by lazy {
|
||||
val codes = (1..7).toList()
|
||||
Collections.rotate(codes, -startDateCalendar.firstDayOfWeek)
|
||||
codes
|
||||
}
|
||||
|
||||
init {
|
||||
inflate(R.layout.task_form_task_scheduling, true)
|
||||
repeatsEverySpinner.adapter = frequencyAdapter
|
||||
|
||||
repeatsEverySpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
frequency = frequency
|
||||
}
|
||||
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
frequency = when (position) {
|
||||
1 -> Task.FREQUENCY_WEEKLY
|
||||
2 -> Task.FREQUENCY_MONTHLY
|
||||
3 -> Task.FREQUENCY_YEARLY
|
||||
else -> Task.FREQUENCY_DAILY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startDateWrapper.setOnClickListener {
|
||||
val datePickerDialog = DatePickerDialog(context, this,
|
||||
startDateCalendar.get(Calendar.YEAR),
|
||||
startDateCalendar.get(Calendar.MONTH),
|
||||
startDateCalendar.get(Calendar.DAY_OF_MONTH))
|
||||
datePickerDialog.setButton(DialogInterface.BUTTON_NEUTRAL, resources.getString(R.string.today)) { _, _ ->
|
||||
if (taskType == Task.TYPE_TODO) {
|
||||
dueDate = Date()
|
||||
} else {
|
||||
startDate = Date()
|
||||
}
|
||||
}
|
||||
if (taskType == Task.TYPE_TODO) {
|
||||
datePickerDialog.setButton(DialogInterface.BUTTON_NEUTRAL, resources.getString(R.string.clear)) { _, _ ->
|
||||
dueDate = null
|
||||
}
|
||||
}
|
||||
datePickerDialog.show()
|
||||
}
|
||||
|
||||
monthlyRepeatDaysButton.setOnClickListener {
|
||||
daysOfMonth = mutableListOf(startDateCalendar.get(Calendar.DATE))
|
||||
weeksOfMonth = null
|
||||
}
|
||||
monthlyRepeatWeeksButton.setOnClickListener {
|
||||
weeksOfMonth = mutableListOf(startDateCalendar.get(Calendar.WEEK_OF_MONTH))
|
||||
daysOfMonth = null
|
||||
}
|
||||
|
||||
orientation = LinearLayout.VERTICAL
|
||||
configureViewsForType()
|
||||
configureViewsForFrequency()
|
||||
}
|
||||
|
||||
private fun configureViewsForType() {
|
||||
startDateTitleView.text = context.getString(if (taskType == Task.TYPE_DAILY) R.string.start_date else R.string.due_date)
|
||||
repeatsEveryWrapper.visibility = if (taskType == Task.TYPE_DAILY) View.VISIBLE else View.GONE
|
||||
}
|
||||
|
||||
override fun onDateSet(view: DatePicker?, year: Int, month: Int, dayOfMonth: Int) {
|
||||
startDateCalendar.set(year, month, dayOfMonth)
|
||||
if (taskType == Task.TYPE_TODO) {
|
||||
dueDate = startDateCalendar.time
|
||||
} else {
|
||||
startDate = startDateCalendar.time
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureViewsForFrequency() {
|
||||
repeatsEveryTitleView.text = context.getText(when (frequency) {
|
||||
Task.FREQUENCY_WEEKLY -> R.string.weeks
|
||||
Task.FREQUENCY_MONTHLY -> R.string.months
|
||||
Task.FREQUENCY_YEARLY -> R.string.years
|
||||
else -> R.string.days
|
||||
})
|
||||
weeklyRepeatWrapper.visibility = if (frequency == Task.FREQUENCY_WEEKLY && taskType == Task.TYPE_DAILY) View.VISIBLE else View.GONE
|
||||
monthlyRepeatWrapper.visibility = if (frequency == Task.FREQUENCY_MONTHLY && taskType == Task.TYPE_DAILY) View.VISIBLE else View.GONE
|
||||
if (frequency == Task.FREQUENCY_WEEKLY) {
|
||||
createWeeklyRepeatViews()
|
||||
} else if (frequency == Task.FREQUENCY_MONTHLY) {
|
||||
if (weeksOfMonth?.isNotEmpty() != true && daysOfMonth?.isNotEmpty() != true) {
|
||||
daysOfMonth = listOf(startDateCalendar.get(Calendar.DATE))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setWeekdayActive(weekday: Int, isActive: Boolean) {
|
||||
when (weekday) {
|
||||
2 -> weeklyRepeat.m = isActive
|
||||
3 -> weeklyRepeat.t = isActive
|
||||
4 -> weeklyRepeat.w = isActive
|
||||
5 -> weeklyRepeat.th = isActive
|
||||
6 -> weeklyRepeat.f = isActive
|
||||
7 -> weeklyRepeat.s = isActive
|
||||
1 -> weeklyRepeat.su = isActive
|
||||
}
|
||||
createWeeklyRepeatViews()
|
||||
}
|
||||
|
||||
private fun isWeekdayActive(weekday: Int): Boolean {
|
||||
return when (weekday) {
|
||||
2 -> weeklyRepeat.m
|
||||
3 -> weeklyRepeat.t
|
||||
4 -> weeklyRepeat.w
|
||||
5 -> weeklyRepeat.th
|
||||
6 -> weeklyRepeat.f
|
||||
7 -> weeklyRepeat.s
|
||||
1 -> weeklyRepeat.su
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWeeklyRepeatViews() {
|
||||
weeklyRepeatWrapper.removeAllViews()
|
||||
val size = 32.dpToPx(context)
|
||||
val lastWeekday = weekdayOrder.last()
|
||||
for (weekdayCode in weekdayOrder) {
|
||||
val button = TextView(context, null, 0, R.style.TaskFormWeekdayButton)
|
||||
val layoutParams = LinearLayout.LayoutParams(size, size)
|
||||
button.layoutParams = layoutParams
|
||||
button.text = weekdays[weekdayCode].first().toUpperCase().toString()
|
||||
val isActive = isWeekdayActive(weekdayCode)
|
||||
if (isActive) {
|
||||
button.background = context.getDrawable(R.drawable.habit_scoring_circle_selected)
|
||||
button.background.mutate().setTint(tintColor)
|
||||
button.setTextColor(ContextCompat.getColor(context, R.color.white))
|
||||
} else {
|
||||
button.background = context.getDrawable(R.drawable.habit_scoring_circle)
|
||||
button.setTextColor(ContextCompat.getColor(context, R.color.gray_100))
|
||||
}
|
||||
button.setOnClickListener {
|
||||
setWeekdayActive(weekdayCode, !isActive)
|
||||
}
|
||||
weeklyRepeatWrapper.addView(button)
|
||||
if (weekdayCode != lastWeekday) {
|
||||
val space = Space(context)
|
||||
val spaceLayoutParams = LinearLayout.LayoutParams(0, LayoutParams.WRAP_CONTENT)
|
||||
spaceLayoutParams.weight = 1f
|
||||
space.layoutParams = spaceLayoutParams
|
||||
weeklyRepeatWrapper.addView(space)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureMonthlyRepeatViews() {
|
||||
val white = ContextCompat.getColor(context, R.color.white)
|
||||
val unselectedText = ContextCompat.getColor(context, R.color.gray_100)
|
||||
val unselectedBackground = ContextCompat.getColor(context, R.color.taskform_gray)
|
||||
if (daysOfMonth != null && daysOfMonth?.isEmpty() != true) {
|
||||
monthlyRepeatDaysButton.setTextColor(white)
|
||||
monthlyRepeatDaysButton.background.mutate().setTint(tintColor)
|
||||
} else {
|
||||
monthlyRepeatDaysButton.setTextColor(unselectedText)
|
||||
monthlyRepeatDaysButton.background.mutate().setTint(unselectedBackground)
|
||||
}
|
||||
if (weeksOfMonth != null && weeksOfMonth?.isEmpty() != true) {
|
||||
monthlyRepeatWeeksButton.setTextColor(white)
|
||||
monthlyRepeatWeeksButton.background.mutate().setTint(tintColor)
|
||||
} else {
|
||||
monthlyRepeatWeeksButton.setTextColor(unselectedText)
|
||||
monthlyRepeatWeeksButton.background.mutate().setTint(unselectedBackground)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue