improve yes/no dialog design

pull/1103/head
Bindu 4 years ago
parent 71f400f587
commit 8036b10ee6

@ -1,36 +1,63 @@
package org.isoron.uhabits.activities.common.dialogs package org.isoron.uhabits.activities.common.dialogs
import android.content.Context import android.content.Context
import android.graphics.Color
import android.graphics.Typeface
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
import android.widget.EditText import android.widget.Button
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry.Companion.NO
import org.isoron.uhabits.core.models.Entry.Companion.SKIP
import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
import org.isoron.uhabits.databinding.CheckmarkDialogBinding
import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.inject.ActivityContext
import org.isoron.uhabits.utils.InterfaceUtils
import org.isoron.uhabits.utils.StyledResources
import javax.inject.Inject import javax.inject.Inject
class CheckmarkDialog class CheckmarkDialog
@Inject constructor( @Inject constructor(
@ActivityContext private val context: Context @ActivityContext private val context: Context,
) { private val preferences: Preferences,
) : View.OnClickListener {
private lateinit var binding: CheckmarkDialogBinding
private lateinit var fontAwesome: Typeface
private val allButtons = mutableListOf<Button>()
private var selectedButton: Button? = null
fun create( fun create(
value: Int,
notes: String, notes: String,
dateString: String,
paletteColor: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback callback: ListHabitsBehavior.CheckMarkDialogCallback
): AlertDialog { ): AlertDialog {
val inflater = LayoutInflater.from(context) binding = CheckmarkDialogBinding.inflate(LayoutInflater.from(context))
val view = inflater.inflate(R.layout.checkmark_dialog, null) fontAwesome = InterfaceUtils.getFontAwesome(context)!!
val etNotes = view.findViewById<EditText>(R.id.etNotes) binding.etNotes.setText(notes)
setUpButtons(value, Color.parseColor(paletteColor.toCsvColor()))
etNotes.setText(notes)
val dialog = AlertDialog.Builder(context) val dialog = AlertDialog.Builder(context)
.setView(view) .setView(binding.root)
.setTitle(R.string.edit_notes) .setTitle(dateString)
.setPositiveButton(R.string.save) { _, _ -> .setPositiveButton(R.string.save) { _, _ ->
val note = etNotes.text.toString() val newValue = when (selectedButton?.id) {
callback.onNotesSaved(note) R.id.yesBtn -> YES_MANUAL
R.id.noBtn -> NO
R.id.skippedBtn -> SKIP
else -> UNKNOWN
}
callback.onNotesSaved(newValue, binding.etNotes.text.toString())
} }
.setNegativeButton(android.R.string.cancel) { _, _ -> .setNegativeButton(android.R.string.cancel) { _, _ ->
callback.onNotesDismissed() callback.onNotesDismissed()
@ -41,10 +68,52 @@ class CheckmarkDialog
.create() .create()
dialog.setOnShowListener { dialog.setOnShowListener {
etNotes.requestFocus() binding.etNotes.requestFocus()
dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE) dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE)
} }
return dialog return dialog
} }
private fun setUpButtons(value: Int, color: Int) {
val sres = StyledResources(context)
val mediumContrastColor = sres.getColor(R.attr.contrast60)
setButtonAttrs(binding.yesBtn, color)
setButtonAttrs(binding.noBtn, mediumContrastColor)
if (preferences.isSkipEnabled) {
setButtonAttrs(binding.skippedBtn, color)
if (value == SKIP) binding.skippedBtn.performClick()
}
if (preferences.areQuestionMarksEnabled) {
setButtonAttrs(binding.questionBtn, mediumContrastColor)
if (value == UNKNOWN) binding.questionBtn.performClick()
}
when (value) {
YES_MANUAL, YES_AUTO -> binding.yesBtn.performClick()
NO -> binding.noBtn.performClick()
}
}
private fun setButtonAttrs(button: Button, color: Int) {
button.apply {
visibility = View.VISIBLE
typeface = fontAwesome
setTextColor(color)
setOnClickListener(this@CheckmarkDialog)
}
allButtons.add(button)
}
override fun onClick(v: View?) {
allButtons.forEach {
if (v?.id == it.id) {
it.isSelected = true
selectedButton = it
} else it.isSelected = false
}
}
} }

@ -235,10 +235,13 @@ class ListHabitsScreen
} }
override fun showCheckmarkDialog( override fun showCheckmarkDialog(
value: Int,
notes: String, notes: String,
dateString: String,
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback callback: ListHabitsBehavior.CheckMarkDialogCallback
) { ) {
checkMarkDialog.create(notes, callback).show() checkMarkDialog.create(value, notes, dateString, color, callback).show()
} }
private fun getExecuteString(command: Command): String? { private fun getExecuteString(command: Command): String? {

@ -39,6 +39,7 @@ import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.Command
import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
@ -173,10 +174,14 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
} }
override fun showCheckmarkDialog( override fun showCheckmarkDialog(
value: Int,
notes: String, notes: String,
dateString: String,
preferences: Preferences,
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback callback: ListHabitsBehavior.CheckMarkDialogCallback
) { ) {
CheckmarkDialog(this@ShowHabitActivity).create(notes, callback).show() CheckmarkDialog(this@ShowHabitActivity, preferences).create(value, notes, dateString, color, callback).show()
} }
override fun showEditHabitScreen(habit: Habit) { override fun showEditHabitScreen(habit: Habit) {

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true">
<shape>
<solid android:color="?attr/contrast40" />
<corners android:radius="4dp"/>
<padding
android:bottom="0dp"
android:left="8dp"
android:right="8dp"
android:top="0dp" />
</shape>
</item>
</selector>

@ -4,15 +4,92 @@
android:gravity="center" android:gravity="center"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="30dp"> android:orientation="vertical"
android:paddingTop="12dp"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<EditText <LinearLayout
android:id="@+id/etNotes"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textCapSentences|textMultiLine" android:orientation="horizontal"
style="@style/TextAppearance.AppCompat.Body1" android:padding="8dp"
android:scrollbars="vertical" android:baselineAligned="false">
android:hint="@string/example_notes"/>
<FrameLayout
style="@style/FormOuterBox"
android:layout_width="0dp"
android:layout_weight="1">
<LinearLayout style="@style/DialogFormInnerBox">
<TextView
style="@style/DialogFormLabel"
android:text="@string/value" />
<LinearLayout
android:orientation="horizontal"
android:gravity="center_horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="8dp">
<Button
android:id="@+id/yesBtn"
android:text="@string/fa_check"
style="@style/CheckmarkDialogBtn"/>
<Button
android:id="@+id/skippedBtn"
android:text="@string/fa_skipped"
android:visibility="gone"
style="@style/CheckmarkDialogBtn"/>
<Button
android:id="@+id/noBtn"
android:text="@string/fa_times"
style="@style/CheckmarkDialogBtn"/>
<Button
android:id="@+id/questionBtn"
android:text="@string/fa_question"
android:visibility="gone"
style="@style/CheckmarkDialogBtn"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp"
android:baselineAligned="false">
<FrameLayout
style="@style/FormOuterBox"
android:layout_width="0dp"
android:layout_weight="1">
<LinearLayout style="@style/DialogFormInnerBox">
<TextView
style="@style/DialogFormLabel"
android:text="@string/notes" />
<EditText
android:id="@+id/etNotes"
android:inputType="textCapSentences|textMultiLine"
style="@style/FormInput"
android:scrollbars="vertical"
android:hint="@string/example_notes"/>
</LinearLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout> </LinearLayout>

@ -232,5 +232,4 @@
<string name="activity_not_found">No app was found to support this action</string> <string name="activity_not_found">No app was found to support this action</string>
<string name="pref_midnight_delay_title">Extend day a few hours past midnight</string> <string name="pref_midnight_delay_title">Extend day a few hours past midnight</string>
<string name="pref_midnight_delay_description">Wait until 3:00 AM to show a new day. Useful if you typically go to sleep after midnight. Requires app restart.</string> <string name="pref_midnight_delay_description">Wait until 3:00 AM to show a new day. Useful if you typically go to sleep after midnight. Requires app restart.</string>
<string name="edit_notes">Edit notes</string>
</resources> </resources>

@ -387,4 +387,16 @@
<item name="android:textSize">@dimen/smallTextSize</item> <item name="android:textSize">@dimen/smallTextSize</item>
</style> </style>
<style name="CheckmarkDialogBtn">
<item name="android:layout_width">48dp</item>
<item name="android:layout_height">48dp</item>
<item name="android:layout_marginTop">8dp</item>
<item name="android:layout_marginBottom">8dp</item>
<item name="android:layout_marginEnd">12dp</item>
<item name="android:textSize">@dimen/regularTextSize</item>
<item name="backgroundTint">@null</item>
<item name="android:background">@drawable/bg_select_button</item>
<item name="selectable">true</item>
</style>
</resources> </resources>

@ -23,6 +23,7 @@ import org.isoron.uhabits.core.commands.CreateRepetitionCommand
import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.HabitType import org.isoron.uhabits.core.models.HabitType
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.models.Timestamp
import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.preferences.Preferences
import org.isoron.uhabits.core.tasks.ExportCSVTask import org.isoron.uhabits.core.tasks.ExportCSVTask
@ -62,9 +63,12 @@ open class ListHabitsBehavior @Inject constructor(
} }
} else { } else {
screen.showCheckmarkDialog( screen.showCheckmarkDialog(
entry.notes entry.value,
) { newNotes -> entry.notes,
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, entry.value, newNotes)) timestamp.toDialogDateString(),
habit.color,
) { newValue, newNotes ->
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, newValue, newNotes))
} }
} }
} }
@ -148,7 +152,7 @@ open class ListHabitsBehavior @Inject constructor(
} }
fun interface CheckMarkDialogCallback { fun interface CheckMarkDialogCallback {
fun onNotesSaved(notes: String) fun onNotesSaved(value: Int, notes: String)
fun onNotesDismissed() {} fun onNotesDismissed() {}
} }
@ -164,7 +168,10 @@ open class ListHabitsBehavior @Inject constructor(
callback: NumberPickerCallback callback: NumberPickerCallback
) )
fun showCheckmarkDialog( fun showCheckmarkDialog(
value: Int,
notes: String, notes: String,
dateString: String,
color: PaletteColor,
callback: CheckMarkDialogCallback callback: CheckMarkDialogCallback
) )

@ -90,13 +90,19 @@ class HistoryCardPresenter(
showNumberPicker(timestamp) showNumberPicker(timestamp)
} else { } else {
val entry = habit.computedEntries.get(timestamp) val entry = habit.computedEntries.get(timestamp)
screen.showCheckmarkDialog(entry.notes) { newNotes -> screen.showCheckmarkDialog(
entry.value,
entry.notes,
timestamp.toDialogDateString(),
preferences,
habit.color,
) { newValue, newNotes ->
commandRunner.run( commandRunner.run(
CreateRepetitionCommand( CreateRepetitionCommand(
habitList, habitList,
habit, habit,
timestamp, timestamp,
entry.value, newValue,
newNotes, newNotes,
), ),
) )
@ -200,7 +206,11 @@ class HistoryCardPresenter(
callback: ListHabitsBehavior.NumberPickerCallback, callback: ListHabitsBehavior.NumberPickerCallback,
) )
fun showCheckmarkDialog( fun showCheckmarkDialog(
value: Int,
notes: String, notes: String,
dateString: String,
preferences: Preferences,
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback, callback: ListHabitsBehavior.CheckMarkDialogCallback,
) )
} }

Loading…
Cancel
Save