mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Implement dialog for Yes/No Habits
This commit is contained in:
@@ -0,0 +1,50 @@
|
|||||||
|
package org.isoron.uhabits.activities.common.dialogs
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE
|
||||||
|
import android.widget.EditText
|
||||||
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||||
|
import org.isoron.uhabits.inject.ActivityContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class CheckmarkDialog
|
||||||
|
@Inject constructor(
|
||||||
|
@ActivityContext private val context: Context
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun create(
|
||||||
|
notes: String,
|
||||||
|
callback: ListHabitsBehavior.CheckMarkDialogCallback
|
||||||
|
): AlertDialog {
|
||||||
|
val inflater = LayoutInflater.from(context)
|
||||||
|
val view = inflater.inflate(R.layout.checkmark_dialog, null)
|
||||||
|
|
||||||
|
val etNotes = view.findViewById<EditText>(R.id.etNotes)
|
||||||
|
|
||||||
|
etNotes.setText(notes)
|
||||||
|
val dialog = AlertDialog.Builder(context)
|
||||||
|
.setView(view)
|
||||||
|
.setTitle(R.string.edit_notes)
|
||||||
|
.setPositiveButton(R.string.save) { _, _ ->
|
||||||
|
val note = etNotes.text.toString()
|
||||||
|
callback.onNotesSaved(note)
|
||||||
|
}
|
||||||
|
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||||
|
callback.onNotesDismissed()
|
||||||
|
}
|
||||||
|
.setOnDismissListener {
|
||||||
|
callback.onNotesDismissed()
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
|
||||||
|
dialog.setOnShowListener {
|
||||||
|
etNotes.requestFocus()
|
||||||
|
dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
return dialog
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -89,7 +89,7 @@ class NumberPickerFactory
|
|||||||
val note = etNotes.text.toString()
|
val note = etNotes.text.toString()
|
||||||
callback.onNumberPicked(v, note)
|
callback.onNumberPicked(v, note)
|
||||||
}
|
}
|
||||||
.setNegativeButton(R.string.cancel) { _, _ ->
|
.setNegativeButton(android.R.string.cancel) { _, _ ->
|
||||||
callback.onNumberPickerDismissed()
|
callback.onNumberPickerDismissed()
|
||||||
}
|
}
|
||||||
.setOnDismissListener {
|
.setOnDismissListener {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import android.content.Intent
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import dagger.Lazy
|
import dagger.Lazy
|
||||||
import org.isoron.uhabits.R
|
import org.isoron.uhabits.R
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog
|
||||||
import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory
|
import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory
|
||||||
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
|
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
|
||||||
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
||||||
@@ -89,6 +90,7 @@ class ListHabitsScreen
|
|||||||
private val importTaskFactory: ImportDataTaskFactory,
|
private val importTaskFactory: ImportDataTaskFactory,
|
||||||
private val colorPickerFactory: ColorPickerDialogFactory,
|
private val colorPickerFactory: ColorPickerDialogFactory,
|
||||||
private val numberPickerFactory: NumberPickerFactory,
|
private val numberPickerFactory: NumberPickerFactory,
|
||||||
|
private val checkMarkDialog: CheckmarkDialog,
|
||||||
private val behavior: Lazy<ListHabitsBehavior>
|
private val behavior: Lazy<ListHabitsBehavior>
|
||||||
) : CommandRunner.Listener,
|
) : CommandRunner.Listener,
|
||||||
ListHabitsBehavior.Screen,
|
ListHabitsBehavior.Screen,
|
||||||
@@ -231,6 +233,13 @@ class ListHabitsScreen
|
|||||||
numberPickerFactory.create(value, unit, notes, callback).show()
|
numberPickerFactory.create(value, unit, notes, callback).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showCheckmarkDialog(
|
||||||
|
notes: String,
|
||||||
|
callback: ListHabitsBehavior.CheckMarkDialogCallback
|
||||||
|
) {
|
||||||
|
checkMarkDialog.create(notes, callback).show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun getExecuteString(command: Command): String? {
|
private fun getExecuteString(command: Command): String? {
|
||||||
when (command) {
|
when (command) {
|
||||||
is ArchiveHabitsCommand -> {
|
is ArchiveHabitsCommand -> {
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ import org.isoron.uhabits.core.preferences.Preferences
|
|||||||
import org.isoron.uhabits.inject.ActivityContext
|
import org.isoron.uhabits.inject.ActivityContext
|
||||||
import org.isoron.uhabits.utils.dim
|
import org.isoron.uhabits.utils.dim
|
||||||
import org.isoron.uhabits.utils.getFontAwesome
|
import org.isoron.uhabits.utils.getFontAwesome
|
||||||
import org.isoron.uhabits.utils.showMessage
|
|
||||||
import org.isoron.uhabits.utils.sres
|
import org.isoron.uhabits.utils.sres
|
||||||
import org.isoron.uhabits.utils.toMeasureSpec
|
import org.isoron.uhabits.utils.toMeasureSpec
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@@ -78,6 +77,8 @@ class CheckmarkButtonView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var onToggle: (Int) -> Unit = {}
|
var onToggle: (Int) -> Unit = {}
|
||||||
|
|
||||||
|
var onEdit: () -> Unit = {}
|
||||||
private var drawer = Drawer()
|
private var drawer = Drawer()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -99,7 +100,7 @@ class CheckmarkButtonView(
|
|||||||
|
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
if (preferences.isShortToggleEnabled) performToggle()
|
if (preferences.isShortToggleEnabled) performToggle()
|
||||||
else showMessage(resources.getString(R.string.long_press_to_toggle))
|
else onEdit()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLongClick(v: View): Boolean {
|
override fun onLongClick(v: View): Boolean {
|
||||||
@@ -133,6 +134,8 @@ class CheckmarkButtonView(
|
|||||||
textAlign = Paint.Align.CENTER
|
textAlign = Paint.Align.CENTER
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val pNotesIndicator: Paint = Paint()
|
||||||
|
|
||||||
fun draw(canvas: Canvas) {
|
fun draw(canvas: Canvas) {
|
||||||
paint.color = when (value) {
|
paint.color = when (value) {
|
||||||
YES_MANUAL, YES_AUTO, SKIP -> color
|
YES_MANUAL, YES_AUTO, SKIP -> color
|
||||||
@@ -142,6 +145,7 @@ class CheckmarkButtonView(
|
|||||||
}
|
}
|
||||||
else -> lowContrastColor
|
else -> lowContrastColor
|
||||||
}
|
}
|
||||||
|
pNotesIndicator.color = color
|
||||||
val id = when (value) {
|
val id = when (value) {
|
||||||
SKIP -> R.string.fa_skipped
|
SKIP -> R.string.fa_skipped
|
||||||
NO -> R.string.fa_times
|
NO -> R.string.fa_times
|
||||||
@@ -176,6 +180,11 @@ class CheckmarkButtonView(
|
|||||||
paint.style = Paint.Style.FILL
|
paint.style = Paint.Style.FILL
|
||||||
canvas.drawText(label, rect.centerX(), rect.centerY(), paint)
|
canvas.drawText(label, rect.centerX(), rect.centerY(), paint)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasNotes) {
|
||||||
|
val cy = 0.8f * em
|
||||||
|
canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,12 @@ class CheckmarkPanelView(
|
|||||||
setupButtons()
|
setupButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var onEdit: (Timestamp) -> Unit = {}
|
||||||
|
set(value) {
|
||||||
|
field = value
|
||||||
|
setupButtons()
|
||||||
|
}
|
||||||
|
|
||||||
override fun createButton(): CheckmarkButtonView = buttonFactory.create()
|
override fun createButton(): CheckmarkButtonView = buttonFactory.create()
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
@@ -84,6 +90,7 @@ class CheckmarkPanelView(
|
|||||||
}
|
}
|
||||||
button.color = color
|
button.color = color
|
||||||
button.onToggle = { value -> onToggle(timestamp, value) }
|
button.onToggle = { value -> onToggle(timestamp, value) }
|
||||||
|
button.onEdit = { onEdit(timestamp) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ class HabitCardView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var notes
|
var notes
|
||||||
get() = numberPanel.notes
|
get() = checkmarkPanel.notes
|
||||||
set(values) {
|
set(values) {
|
||||||
checkmarkPanel.notes = values
|
checkmarkPanel.notes = values
|
||||||
numberPanel.notes = values
|
numberPanel.notes = values
|
||||||
@@ -150,7 +150,11 @@ class HabitCardView(
|
|||||||
checkmarkPanel = checkmarkPanelFactory.create().apply {
|
checkmarkPanel = checkmarkPanelFactory.create().apply {
|
||||||
onToggle = { timestamp, value ->
|
onToggle = { timestamp, value ->
|
||||||
triggerRipple(timestamp)
|
triggerRipple(timestamp)
|
||||||
habit?.let { behavior.onToggle(it, timestamp, value, "") }
|
habit?.let { behavior.onToggle(it, timestamp, value) }
|
||||||
|
}
|
||||||
|
onEdit = { timestamp ->
|
||||||
|
triggerRipple(timestamp)
|
||||||
|
habit?.let { behavior.onEdit(it, timestamp) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ class NumberButtonView(
|
|||||||
pNumber.color = activeColor
|
pNumber.color = activeColor
|
||||||
pNumber.typeface = typeface
|
pNumber.typeface = typeface
|
||||||
pUnit.color = activeColor
|
pUnit.color = activeColor
|
||||||
pNotesIndicator.color = activeColor
|
pNotesIndicator.color = color
|
||||||
|
|
||||||
if (units.isBlank()) {
|
if (units.isBlank()) {
|
||||||
rect.set(0f, 0f, width.toFloat(), height.toFloat())
|
rect.set(0f, 0f, width.toFloat(), height.toFloat())
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.isoron.uhabits.HabitsApplication
|
|||||||
import org.isoron.uhabits.R
|
import org.isoron.uhabits.R
|
||||||
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
||||||
import org.isoron.uhabits.activities.HabitsDirFinder
|
import org.isoron.uhabits.activities.HabitsDirFinder
|
||||||
|
import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog
|
||||||
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
|
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
|
||||||
import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
|
import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
|
||||||
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
||||||
@@ -170,6 +171,13 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
|||||||
NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, callback).show()
|
NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, callback).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showCheckmarkDialog(
|
||||||
|
notes: String,
|
||||||
|
callback: ListHabitsBehavior.CheckMarkDialogCallback
|
||||||
|
) {
|
||||||
|
CheckmarkDialog(this@ShowHabitActivity).create(notes, callback).show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun showEditHabitScreen(habit: Habit) {
|
override fun showEditHabitScreen(habit: Habit) {
|
||||||
startActivity(IntentFactory().startEditActivity(this@ShowHabitActivity, habit))
|
startActivity(IntentFactory().startEditActivity(this@ShowHabitActivity, habit))
|
||||||
}
|
}
|
||||||
|
|||||||
18
uhabits-android/src/main/res/layout/checkmark_dialog.xml
Normal file
18
uhabits-android/src/main/res/layout/checkmark_dialog.xml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="30dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/etNotes"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:inputType="textCapSentences|textMultiLine"
|
||||||
|
style="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
android:hint="@string/example_notes"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -55,7 +55,6 @@
|
|||||||
<string name="clear">Clear</string>
|
<string name="clear">Clear</string>
|
||||||
<string name="reminder">Reminder</string>
|
<string name="reminder">Reminder</string>
|
||||||
<string name="save">Save</string>
|
<string name="save">Save</string>
|
||||||
<string name="cancel">Cancel</string>
|
|
||||||
<string name="streaks">Streaks</string>
|
<string name="streaks">Streaks</string>
|
||||||
<string name="no_habits_found">You have no active habits</string>
|
<string name="no_habits_found">You have no active habits</string>
|
||||||
<string name="no_habits_left_to_do">You\'re all done for today!</string>
|
<string name="no_habits_left_to_do">You\'re all done for today!</string>
|
||||||
@@ -233,4 +232,5 @@
|
|||||||
<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>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.isoron.uhabits.core.commands.CommandRunner
|
|||||||
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
|
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.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
|
||||||
@@ -48,15 +49,24 @@ open class ListHabitsBehavior @Inject constructor(
|
|||||||
|
|
||||||
fun onEdit(habit: Habit, timestamp: Timestamp?) {
|
fun onEdit(habit: Habit, timestamp: Timestamp?) {
|
||||||
val entries = habit.computedEntries.get(timestamp!!)
|
val entries = habit.computedEntries.get(timestamp!!)
|
||||||
val oldValue = entries.value.toDouble()
|
|
||||||
val notes = entries.notes
|
val notes = entries.notes
|
||||||
screen.showNumberPicker(
|
if (habit.type == HabitType.NUMERICAL) {
|
||||||
oldValue / 1000,
|
val oldValue = entries.value.toDouble()
|
||||||
habit.unit,
|
screen.showNumberPicker(
|
||||||
notes
|
oldValue / 1000,
|
||||||
) { newValue: Double, newNotes:String, ->
|
habit.unit,
|
||||||
val value = (newValue * 1000).roundToInt()
|
notes
|
||||||
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes))
|
) { newValue: Double, newNotes:String, ->
|
||||||
|
val value = (newValue * 1000).roundToInt()
|
||||||
|
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val value = entries.value
|
||||||
|
screen.showCheckmarkDialog(
|
||||||
|
notes
|
||||||
|
) { newNotes ->
|
||||||
|
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,9 +116,10 @@ open class ListHabitsBehavior @Inject constructor(
|
|||||||
if (prefs.isFirstRun) onFirstRun()
|
if (prefs.isFirstRun) onFirstRun()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int, notes: String) {
|
fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int) {
|
||||||
|
val notes = habit.computedEntries.get(timestamp!!).notes
|
||||||
commandRunner.run(
|
commandRunner.run(
|
||||||
CreateRepetitionCommand(habitList, habit, timestamp!!, value, notes)
|
CreateRepetitionCommand(habitList, habit, timestamp, value, notes)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +148,11 @@ open class ListHabitsBehavior @Inject constructor(
|
|||||||
fun onNumberPickerDismissed() {}
|
fun onNumberPickerDismissed() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun interface CheckMarkDialogCallback {
|
||||||
|
fun onNotesSaved(notes: String)
|
||||||
|
fun onNotesDismissed() {}
|
||||||
|
}
|
||||||
|
|
||||||
interface Screen {
|
interface Screen {
|
||||||
fun showHabitScreen(h: Habit)
|
fun showHabitScreen(h: Habit)
|
||||||
fun showIntroScreen()
|
fun showIntroScreen()
|
||||||
@@ -147,6 +163,10 @@ open class ListHabitsBehavior @Inject constructor(
|
|||||||
notes: String,
|
notes: String,
|
||||||
callback: NumberPickerCallback
|
callback: NumberPickerCallback
|
||||||
)
|
)
|
||||||
|
fun showCheckmarkDialog(
|
||||||
|
notes: String,
|
||||||
|
callback: CheckMarkDialogCallback
|
||||||
|
)
|
||||||
|
|
||||||
fun showSendBugReportToDeveloperScreen(log: String)
|
fun showSendBugReportToDeveloperScreen(log: String)
|
||||||
fun showSendFileScreen(filename: String)
|
fun showSendFileScreen(filename: String)
|
||||||
|
|||||||
@@ -162,5 +162,9 @@ class HistoryCardPresenter(
|
|||||||
notes: String,
|
notes: String,
|
||||||
callback: ListHabitsBehavior.NumberPickerCallback,
|
callback: ListHabitsBehavior.NumberPickerCallback,
|
||||||
)
|
)
|
||||||
|
fun showCheckmarkDialog(
|
||||||
|
notes: String,
|
||||||
|
callback: ListHabitsBehavior.CheckMarkDialogCallback,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user