refactor based on comments

pull/610/head
KristianTashkov 5 years ago
parent 81d4b11ece
commit 4d282c7a88

@ -20,7 +20,6 @@
package org.isoron.uhabits.activities.common.dialogs
import android.content.*
import android.graphics.*
import android.view.*
import android.widget.*
import androidx.appcompat.app.*
@ -36,48 +35,54 @@ class CheckmarkOptionPickerFactory
@Inject constructor(
@ActivityContext private val context: Context
) {
fun create(habitName: String,
fun create(habit: Habit,
habitTimestamp: String,
value: Int,
callback: ListHabitsBehavior.CheckmarkOptionsCallback): AlertDialog {
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.checkmark_option_picker_dialog, null)
val title = context.resources.getString(
R.string.choose_checkmark_option, habitName, habitTimestamp)
val dialog = AlertDialog.Builder(context)
.setView(view)
.setTitle(title)
.setTitle(habit.name)
.setOnDismissListener{
callback.onCheckmarkOptionDismissed()
}
.create()
val buttonValues = mapOf(
R.id.check_button to Checkmark.CHECKED_EXPLICITLY,
R.id.yes_button to Checkmark.CHECKED_EXPLICITLY,
R.id.skip_button to Checkmark.SKIPPED_EXPLICITLY,
R.id.fail_button to Checkmark.FAILED_EXPLICITLY_NECESSARY,
R.id.no_button to Checkmark.UNCHECKED_EXPLICITLY_NECESSARY,
R.id.clear_button to Checkmark.UNCHECKED
)
val valuesToButton = mapOf(
Checkmark.CHECKED_EXPLICITLY to R.id.check_button,
Checkmark.CHECKED_EXPLICITLY to R.id.yes_button,
Checkmark.SKIPPED_EXPLICITLY to R.id.skip_button ,
Checkmark.FAILED_EXPLICITLY_NECESSARY to R.id.fail_button,
Checkmark.FAILED_EXPLICITLY_UNNECESSARY to R.id.fail_button
Checkmark.UNCHECKED_EXPLICITLY_NECESSARY to R.id.no_button,
Checkmark.UNCHECKED_EXPLICITLY_UNNECESSARY to R.id.no_button
)
for ((buttonId, buttonValue) in buttonValues) {
val button = view.findViewById<Button>(buttonId)
var textStyle = Typeface.NORMAL
button.setOnClickListener{
callback.onCheckmarkOptionPicked(buttonValue)
dialog.dismiss()
}
if (valuesToButton.containsKey(value) && valuesToButton[value] == buttonId)
textStyle = Typeface.BOLD
button.isPressed = (
valuesToButton.containsKey(value) &&
valuesToButton[value] == buttonId)
button.typeface = InterfaceUtils.getFontAwesome(context)
}
button.setTypeface(InterfaceUtils.getFontAwesome(context), textStyle)
val questionTextView = view.findViewById<TextView>(R.id.choose_checkmark_question_textview)
var question = context.resources.getString(R.string.default_checkmark_option_question)
if (habit.question.isNotEmpty()) {
question = habit.question.trim('?')
}
val questionFullText = context.resources.getString(
R.string.choose_checkmark_question, question, habitTimestamp)
questionTextView.text = questionFullText
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)

@ -349,18 +349,18 @@ public class HistoryChart extends ScrollableChart
headerOverflow = Math.max(0, headerOverflow - columnWidth);
}
private boolean isFailed(int checkmark)
private boolean isNotCompleted(int checkmark)
{
return (checkmark == 0 ||
(!isNumerical && checkmark == FAILED_EXPLICITLY_NECESSARY));
(!isNumerical && checkmark == UNCHECKED_EXPLICITLY_NECESSARY));
}
private boolean isImplicitlySuccessful(int checkmark)
private boolean isImplicitlyCompleted(int checkmark)
{
if (isNumerical) return checkmark < target;
return (checkmark == SKIPPED_EXPLICITLY ||
checkmark == FAILED_EXPLICITLY_UNNECESSARY ||
checkmark == UNCHECKED_EXPLICITLY_UNNECESSARY ||
checkmark == CHECKED_IMPLICITLY);
}
@ -373,8 +373,8 @@ public class HistoryChart extends ScrollableChart
else
{
int checkmark = checkmarks[checkmarkOffset];
if(isFailed(checkmark)) pSquareBg.setColor(colors[0]);
else if(isImplicitlySuccessful(checkmark))
if(isNotCompleted(checkmark)) pSquareBg.setColor(colors[0]);
else if(isImplicitlyCompleted(checkmark))
{
pSquareBg.setColor(isNumerical ? textColor : colors[1]);
}

@ -205,11 +205,11 @@ class ListHabitsScreen
numberPickerFactory.create(value, unit, callback).show()
}
override fun showCheckmarkOptions(habitName: String,
override fun showCheckmarkOptions(habit: Habit,
timestamp: Timestamp,
value: Int,
callback: ListHabitsBehavior.CheckmarkOptionsCallback) {
checkmarkOptionPickerFactory.create(habitName, timestamp.toString(), value, callback).show()
checkmarkOptionPickerFactory.create(habit, timestamp.toString(), value, callback).show()
}
@StringRes

@ -119,7 +119,7 @@ class CheckmarkButtonView(
paint.color = when (value) {
CHECKED_EXPLICITLY -> color
FAILED_EXPLICITLY_NECESSARY -> lowContrastColor
UNCHECKED_EXPLICITLY_NECESSARY -> lowContrastColor
UNCHECKED -> lowContrastColor
else -> lighterColor
}
@ -132,7 +132,7 @@ class CheckmarkButtonView(
val id = when (value) {
SKIPPED_EXPLICITLY -> R.string.fa_skipped
UNCHECKED -> unchecked_symbol
FAILED_EXPLICITLY_NECESSARY -> R.string.fa_times
UNCHECKED_EXPLICITLY_NECESSARY -> R.string.fa_times
CHECKED_IMPLICITLY -> implicitCheckedSymbol
else -> R.string.fa_check
}

@ -97,7 +97,7 @@ public class ShowHabitScreen extends BaseScreen
{
CheckmarkList checkmarks = habit.getCheckmarks();
int oldValue = checkmarks.getValues(timestamp, timestamp)[0];
checkmarkOptionPickerFactory.create(habit.getName(), timestamp.toString(), oldValue,
checkmarkOptionPickerFactory.create(habit, timestamp.toString(), oldValue,
newValue ->
{
behavior.get().onCreateRepetition(timestamp, newValue);

@ -108,7 +108,7 @@ class AndroidNotificationTray
R.drawable.ic_action_cancel,
context.getString(R.string.no),
pendingIntents.setYesNoValue(
habit, timestamp, Checkmark.FAILED_EXPLICITLY_NECESSARY))
habit, timestamp, Checkmark.UNCHECKED_EXPLICITLY_NECESSARY))
}
val wearableBg = decodeResource(context.resources, R.drawable.stripe)

@ -67,7 +67,7 @@ class YesNoCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.CheckmarkOpt
val oldValue = data.habit.checkmarks.getValues(data.timestamp, data.timestamp)[0]
val checkmarkOptionsPickerFactory = CheckmarkOptionPickerFactory(context)
checkmarkOptionsPickerFactory.create(
data.habit.name, data.timestamp.toString(), oldValue, this).show()
data.habit, data.timestamp.toString(), oldValue, this).show()
}
companion object {

@ -82,14 +82,14 @@ public class CheckmarkWidgetView extends HabitWidgetView {
setShadowAlpha(0x4f);
frame.setBackgroundDrawable(background);
break;
case Checkmark.FAILED_EXPLICITLY_NECESSARY:
case Checkmark.UNCHECKED_EXPLICITLY_NECESSARY:
bgColor = res.getColor(R.attr.highlightedBackgroundColor);
fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f);
break;
case Checkmark.SKIPPED_EXPLICITLY:
case Checkmark.CHECKED_IMPLICITLY:
case Checkmark.FAILED_EXPLICITLY_UNNECESSARY:
case Checkmark.UNCHECKED_EXPLICITLY_UNNECESSARY:
bgColor = lighterActiveColor;
fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f);
@ -134,13 +134,13 @@ public class CheckmarkWidgetView extends HabitWidgetView {
if (isNumerical) return NumberButtonViewKt.toShortString(checkmarkValue / 1000.0);
switch (checkmarkState) {
case Checkmark.CHECKED_EXPLICITLY:
case Checkmark.FAILED_EXPLICITLY_UNNECESSARY:
case Checkmark.UNCHECKED_EXPLICITLY_UNNECESSARY:
return getResources().getString(R.string.fa_check);
case Checkmark.CHECKED_IMPLICITLY:
return getResources().getString(implicitCheckedSymbol);
case Checkmark.SKIPPED_EXPLICITLY:
return getResources().getString(R.string.fa_skipped);
case Checkmark.FAILED_EXPLICITLY_NECESSARY:
case Checkmark.UNCHECKED_EXPLICITLY_NECESSARY:
return getResources().getString(R.string.fa_times);
case Checkmark.UNCHECKED:
default:

@ -20,49 +20,64 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:gravity="center"
android:paddingHorizontal="5dp"
android:paddingVertical="25dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:divider="?android:dividerVertical"
android:showDividers="middle">
android:gravity="center"
android:orientation="vertical"
android:paddingHorizontal="5dp"
android:paddingVertical="20dp">
<Button
android:id="@+id/check_button"
style="@style/Widget.AppCompat.Button.Borderless"
<TextView
android:id="@+id/choose_checkmark_question_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/done_button_text"
app:cornerRadius="0dp" />
android:paddingBottom="5dp"
android:text="@string/default_checkmark_option_question"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
<Button
android:id="@+id/fail_button"
style="@style/Widget.AppCompat.Button.Borderless"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/fail_button_text"
app:cornerRadius="0dp" />
android:divider="?android:dividerVertical"
android:gravity="center"
android:orientation="horizontal"
android:showDividers="middle">
<Button
android:id="@+id/skip_button"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/skip_button_text"
app:cornerRadius="0dp" />
<Button
android:id="@+id/yes_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/yes_button_text"
app:cornerRadius="0dp" />
<Button
android:id="@+id/no_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/no_button_text"
app:cornerRadius="0dp" />
<Button
android:id="@+id/clear_button"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/delete_button_text"
app:cornerRadius="0dp" />
<Button
android:id="@+id/skip_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/skip_button_text"
app:cornerRadius="0dp" />
<Button
android:id="@+id/clear_button"
style="@style/Widget.AppCompat.Button.Borderless.Colored"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/delete_button_text"
app:cornerRadius="0dp" />
</LinearLayout>
</LinearLayout>

@ -164,7 +164,7 @@
<string name="export">Export</string>
<string name="long_press_to_edit">Press-and-hold to change the value</string>
<string name="change_value">Change value</string>
<string name="choose_checkmark_option">%1$s on %2$s</string>
<string name="choose_checkmark_question">%1$s on %2$s?</string>
<string name="calendar">Calendar</string>
<string name="unit">Unit</string>
<string name="example_question_boolean">e.g. Did you exercise today?</string>
@ -197,8 +197,9 @@
<string name="every_month">Every month</string>
<string name="validation_cannot_be_blank">Cannot be blank</string>
<string name="today">Today</string>
<string name="done_button_text">&#xf14a;\nDone</string>
<string name="fail_button_text">&#xf057;\nFail</string>
<string name="yes_button_text">&#xf14a;\nYes</string>
<string name="no_button_text">&#xf057;\nNo</string>
<string name="skip_button_text">&#xf146;\nSkip</string>
<string name="delete_button_text">&#xf05e;\nDelete</string>
<string name="default_checkmark_option_question">Have you completed this habit</string>
</resources>

@ -38,16 +38,16 @@ import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
public final class Checkmark
{
/**
* Indicates that there was a failed repetition at the timestamp and a
* Indicates that there was a explicit unchecked repetition at the timestamp and a
* repetition was expected.
*/
public static final int FAILED_EXPLICITLY_NECESSARY = 5;
public static final int UNCHECKED_EXPLICITLY_NECESSARY = 5;
/**
* Indicates that there was a failed repetition at the timestamp and a
* Indicates that there was a explicit unchecked repetition at the timestamp and a
* repetition wasn't expected.
*/
public static final int FAILED_EXPLICITLY_UNNECESSARY = 4;
public static final int UNCHECKED_EXPLICITLY_UNNECESSARY = 4;
/**
* Indicates that there was an explicit skip at the timestamp.
@ -77,7 +77,7 @@ public final class Checkmark
* The value of the checkmark.
* <p>
* For boolean habits, this equals either UNCHECKED, SKIPPED_EXPLICITLY, CHECKED_EXPLICITLY,
* CHECKED_IMPLICITLY, FAILED_EXPLICITLY_UNNECESSARY, FAILED_EXPLICITLY_NECESSARY.
* CHECKED_IMPLICITLY, UNCHECKED_EXPLICITLY_UNNECESSARY, UNCHECKED_EXPLICITLY_NECESSARY.
* <p>
* For numerical habits, this number is stored in thousandths. That
* is, if the user enters value 1.50 on the app, it is stored as 1500.

@ -80,11 +80,11 @@ public abstract class CheckmarkList
Timestamp date = rep.getTimestamp();
int offset = date.daysUntil(today);
int checkmarkValue = rep.getValue();
if (checkmarkValue == FAILED_EXPLICITLY_NECESSARY)
if (checkmarkValue == UNCHECKED_EXPLICITLY_NECESSARY)
{
int oldValue = checkmarks.get(offset).getValue();
checkmarkValue = (oldValue == CHECKED_IMPLICITLY) ?
FAILED_EXPLICITLY_UNNECESSARY : FAILED_EXPLICITLY_NECESSARY;
UNCHECKED_EXPLICITLY_UNNECESSARY : UNCHECKED_EXPLICITLY_NECESSARY;
}
checkmarks.set(offset, new Checkmark(date, checkmarkValue));
}
@ -386,14 +386,14 @@ public abstract class CheckmarkList
private void computeYesNo(Repetition[] reps)
{
ArrayList<Interval> intervals;
List<Repetition> successful_repetitions = new ArrayList<>();
List<Repetition> explicitlyCheckedRepetitions = new ArrayList<>();
for (Repetition rep : reps)
{
if (rep.getValue() == CHECKED_EXPLICITLY)
successful_repetitions.add(rep);
explicitlyCheckedRepetitions.add(rep);
}
intervals = buildIntervals(
habit.getFrequency(), successful_repetitions.toArray(new Repetition[0]));
habit.getFrequency(), explicitlyCheckedRepetitions.toArray(new Repetition[0]));
snapIntervalsTogether(intervals);
add(buildCheckmarksFromIntervals(reps, intervals));
}

@ -331,7 +331,7 @@ public class Habit
else
return todayCheckmark / 1000.0 <= data.targetValue;
}
else return (todayCheckmark != UNCHECKED);
else return (todayCheckmark != UNCHECKED && todayCheckmark != UNCHECKED_EXPLICITLY_NECESSARY);
}
public synchronized boolean isNumerical()

@ -30,7 +30,7 @@ import java.util.GregorianCalendar;
import static org.isoron.uhabits.core.utils.StringUtils.defaultToStringStyle;
/**
* Represents a record that the user has performed, failed to perform or skipped a certain habit at
* Represents a record that the user has performed, didn't perform or skipped a certain habit at
* a certain date.
*/
public final class Repetition
@ -44,7 +44,7 @@ public final class Repetition
* For boolean habits, this equals:
* Checkmark.CHECKED_EXPLICITLY if performed
* Checkmark.SKIPPED_EXPLICITLY if skipped.
* Checkmark.FAILED_EXPLICITLY_NECESSARY if failed.
* Checkmark.UNCHECKED_EXPLICITLY_NECESSARY if not performed.
* For numerical habits, this number is stored in thousandths. That
* is, if the user enters value 1.50 on the app, it is here stored as 1500.
*/

@ -113,7 +113,7 @@ public abstract class RepetitionList
* If the list is empty, returns null. Repetitions in the future are
* discarded.
*
* @return oldest sucessful repetition in the list, or null if list is empty.
* @return oldest successful repetition in the list, or null if list is empty.
*/
@Nullable
public abstract Repetition getOldestSuccessful();

@ -286,7 +286,7 @@ public abstract class ScoreList implements Iterable<Score>
else
{
if (value == Checkmark.UNCHECKED ||
value == Checkmark.FAILED_EXPLICITLY_NECESSARY)
value == Checkmark.UNCHECKED_EXPLICITLY_NECESSARY)
value = 0;
else if (value == Checkmark.SKIPPED_EXPLICITLY)
skip_calculation = true;

@ -131,7 +131,7 @@ public abstract class StreakList
{
ArrayList<Timestamp> list = new ArrayList<>();
Timestamp current = beginning;
Timestamp lastSuccesful = beginning;
Timestamp lastChecked = beginning;
boolean isInStreak = false;
for (int i = checks.length - 1; i >= 0; --i)
@ -139,19 +139,19 @@ public abstract class StreakList
boolean isCurrentChecked = (
checks[i] == Checkmark.CHECKED_EXPLICITLY ||
checks[i] == Checkmark.CHECKED_IMPLICITLY ||
checks[i] == Checkmark.FAILED_EXPLICITLY_UNNECESSARY
checks[i] == Checkmark.UNCHECKED_EXPLICITLY_UNNECESSARY
);
boolean isCurrentFailed = (
boolean isCurrentUnchecked= (
checks[i] == Checkmark.UNCHECKED ||
checks[i] == Checkmark.FAILED_EXPLICITLY_NECESSARY
checks[i] == Checkmark.UNCHECKED_EXPLICITLY_NECESSARY
);
if (habit.getData().type == Habit.NUMBER_HABIT || isCurrentChecked)
lastSuccesful = current;
lastChecked = current;
if (isInStreak && isCurrentFailed)
if (isInStreak && isCurrentUnchecked)
{
list.add(lastSuccesful);
list.add(lastChecked);
isInStreak = false;
}
if (!isInStreak && isCurrentChecked)
@ -164,7 +164,7 @@ public abstract class StreakList
}
if (isInStreak)
list.add(lastSuccesful);
list.add(lastChecked);
return list;
}

@ -160,7 +160,7 @@ public class ListHabitsBehavior
{
CheckmarkList checkmarks = habit.getCheckmarks();
int oldValue = checkmarks.getValues(timestamp, timestamp)[0];
screen.showCheckmarkOptions(habit.getName(), timestamp, oldValue, newValue ->
screen.showCheckmarkOptions(habit, timestamp, oldValue, newValue ->
{
commandRunner.execute(
new CreateRepetitionCommand(habitList, habit, timestamp, newValue),
@ -212,7 +212,7 @@ public class ListHabitsBehavior
@NonNull String unit,
@NonNull NumberPickerCallback callback);
void showCheckmarkOptions(String habitName,
void showCheckmarkOptions(Habit habit,
Timestamp timestamp,
int value,
@NonNull CheckmarkOptionsCallback callback);

Loading…
Cancel
Save