From 19e221bb328523cf15175847a0e49292fe04fade Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Wed, 23 Dec 2020 10:06:31 -0600 Subject: [PATCH] ShowHabitActivity: Re-enable menus and actions --- .../common/views/HistoryChartTest.java | 24 +-- .../common/dialogs/HistoryEditorDialog.java | 21 +- .../activities/common/views/HistoryChart.java | 25 ++- .../habits/show/ShowHabitActivity.kt | 188 +++++------------- .../activities/habits/show/ShowHabitMenu.kt | 61 ++++++ .../habits/show/ShowHabitScreen.java | 156 --------------- .../activities/habits/show/ShowHabitScreen.kt | 83 ++++++++ .../activities/habits/show/ShowHabitView.kt | 135 +++++++++++++ .../habits/show/ShowHabitsMenu.java | 94 --------- .../isoron/uhabits/utils/ViewExtensions.kt | 19 ++ .../ui/callbacks/OnToggleCheckmarkListener.kt | 26 +++ .../habits/show/ShowHabitBehavior.java | 87 -------- .../screens/habits/show/ShowHabitBehavior.kt | 95 +++++++++ .../habits/show/ShowHabitMenuBehavior.java | 146 -------------- .../habits/show/ShowHabitMenuBehavior.kt | 91 +++++++++ .../show/ShowHabitMenuBehaviorTest.java | 3 +- 16 files changed, 599 insertions(+), 655 deletions(-) create mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java create mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.kt create mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/callbacks/OnToggleCheckmarkListener.kt delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.kt delete mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java create mode 100644 android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.kt diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/HistoryChartTest.java b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/HistoryChartTest.java index 10dd36c3a..e9acf0dc7 100644 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/HistoryChartTest.java +++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/HistoryChartTest.java @@ -24,6 +24,7 @@ import androidx.test.filters.*; import org.isoron.uhabits.*; import org.isoron.uhabits.core.models.*; +import org.isoron.uhabits.core.ui.callbacks.*; import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.utils.*; import org.junit.*; @@ -43,7 +44,7 @@ public class HistoryChartTest extends BaseViewTest Timestamp today; - private HistoryChart.Controller controller; + private OnToggleCheckmarkListener onToggleCheckmarkListener; @Override @Before @@ -61,8 +62,8 @@ public class HistoryChartTest extends BaseViewTest chart.setColor(PaletteUtilsKt.toFixedAndroidColor(habit.getColor())); measureView(chart, dpToPixels(400), dpToPixels(200)); - controller = mock(HistoryChart.Controller.class); - chart.setController(controller); + onToggleCheckmarkListener = mock(OnToggleCheckmarkListener.class); + chart.setOnToggleCheckmarkListener(onToggleCheckmarkListener); } @Test @@ -72,21 +73,16 @@ public class HistoryChartTest extends BaseViewTest chart.tap(dpToPixels(118), dpToPixels(13)); // header chart.tap(dpToPixels(336), dpToPixels(60)); // tomorrow's square chart.tap(dpToPixels(370), dpToPixels(60)); // right axis - verifyNoMoreInteractions(controller); + verifyNoMoreInteractions(onToggleCheckmarkListener); } @Test public void tapDate_withEditableView() throws Throwable { chart.setIsEditable(true); - - chart.tap(dpToPixels(340), dpToPixels(40)); - verify(controller).onToggleCheckmark(today, Checkmark.SKIP); - chart.tap(dpToPixels(340), dpToPixels(40)); - verify(controller).onToggleCheckmark(today, Checkmark.NO); chart.tap(dpToPixels(340), dpToPixels(40)); - verify(controller).onToggleCheckmark(today, Checkmark.YES_MANUAL); - verifyNoMoreInteractions(controller); + verify(onToggleCheckmarkListener).onToggleCheckmark(today, Checkmark.SKIP); + verifyNoMoreInteractions(onToggleCheckmarkListener); } @Test @@ -95,8 +91,8 @@ public class HistoryChartTest extends BaseViewTest chart.setIsEditable(true); chart.setCheckmarks(new int[]{}); chart.tap(dpToPixels(340), dpToPixels(40)); - verify(controller).onToggleCheckmark(today, Checkmark.YES_MANUAL); - verifyNoMoreInteractions(controller); + verify(onToggleCheckmarkListener).onToggleCheckmark(today, Checkmark.YES_MANUAL); + verifyNoMoreInteractions(onToggleCheckmarkListener); } @Test @@ -104,7 +100,7 @@ public class HistoryChartTest extends BaseViewTest { chart.setIsEditable(false); chart.tap(dpToPixels(340), dpToPixels(40)); - verifyNoMoreInteractions(controller); + verifyNoMoreInteractions(onToggleCheckmarkListener); } @Test diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java index 9681f72fa..3db266651 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.java @@ -34,7 +34,9 @@ import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.preferences.*; import org.isoron.uhabits.core.tasks.*; +import org.isoron.uhabits.core.ui.callbacks.*; import org.isoron.uhabits.utils.*; +import org.jetbrains.annotations.*; import static org.isoron.androidbase.utils.InterfaceUtils.*; @@ -48,7 +50,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment HistoryChart historyChart; @NonNull - private Controller controller; + private OnToggleCheckmarkListener onToggleCheckmarkListener; private HabitList habitList; @@ -58,7 +60,13 @@ public class HistoryEditorDialog extends AppCompatDialogFragment public HistoryEditorDialog() { - this.controller = new Controller() {}; + this.onToggleCheckmarkListener = new OnToggleCheckmarkListener() + { + @Override + public void onToggleCheckmark(@NotNull Timestamp timestamp, int value) + { + } + }; } @Override @@ -80,7 +88,7 @@ public class HistoryEditorDialog extends AppCompatDialogFragment prefs = app.getComponent().getPreferences(); historyChart = new HistoryChart(context); - historyChart.setController(controller); + historyChart.setOnToggleCheckmarkListener(onToggleCheckmarkListener); historyChart.setFirstWeekday(prefs.getFirstWeekday()); historyChart.setSkipEnabled(prefs.isSkipEnabled()); @@ -144,10 +152,9 @@ public class HistoryEditorDialog extends AppCompatDialogFragment outState.putParcelable("historyChart", historyChart.onSaveInstanceState()); } - public void setController(@NonNull Controller controller) + public void setOnToggleCheckmarkListener(@NonNull OnToggleCheckmarkListener onToggleCheckmarkListener) { - this.controller = controller; - if (historyChart != null) historyChart.setController(controller); + this.onToggleCheckmarkListener = onToggleCheckmarkListener; } public void setHabit(@Nullable Habit habit) @@ -161,8 +168,6 @@ public class HistoryEditorDialog extends AppCompatDialogFragment taskRunner.execute(new RefreshTask()); } - public interface Controller extends HistoryChart.Controller {} - private class RefreshTask implements Task { public int[] checkmarks; diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java index ddc5d4f56..7d2ef2e9c 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/HistoryChart.java @@ -27,12 +27,15 @@ import android.util.*; import android.view.*; import androidx.annotation.*; +import androidx.annotation.Nullable; import org.isoron.androidbase.utils.*; import org.isoron.uhabits.*; import org.isoron.uhabits.core.models.*; +import org.isoron.uhabits.core.ui.callbacks.*; import org.isoron.uhabits.core.utils.*; import org.isoron.uhabits.utils.*; +import org.jetbrains.annotations.*; import java.text.*; import java.util.*; @@ -100,7 +103,7 @@ public class HistoryChart extends ScrollableChart private int firstWeekday = Calendar.SUNDAY; @NonNull - private Controller controller; + private OnToggleCheckmarkListener onToggleCheckmarkListener; private boolean skipsEnabled; @@ -159,10 +162,9 @@ public class HistoryChart extends ScrollableChart newValue = Repetition.nextToggleValueWithSkip(checkmarks[offset]); else newValue = Repetition.nextToggleValueWithoutSkip(checkmarks[offset]); - checkmarks[offset] = newValue; } - controller.onToggleCheckmark(timestamp, newValue); + onToggleCheckmarkListener.onToggleCheckmark(timestamp, newValue); postInvalidate(); return true; @@ -199,9 +201,9 @@ public class HistoryChart extends ScrollableChart postInvalidate(); } - public void setController(@NonNull Controller controller) + public void setOnToggleCheckmarkListener(@NonNull OnToggleCheckmarkListener onToggleCheckmarkListener) { - this.controller = controller; + this.onToggleCheckmarkListener = onToggleCheckmarkListener; } public void setNumerical(boolean numerical) @@ -450,7 +452,13 @@ public class HistoryChart extends ScrollableChart { isEditable = false; checkmarks = new int[0]; - controller = new Controller() {}; + onToggleCheckmarkListener = new OnToggleCheckmarkListener() + { + @Override + public void onToggleCheckmark(@NotNull Timestamp timestamp, int value) + { + } + }; target = 2; initColors(); @@ -552,9 +560,4 @@ public class HistoryChart extends ScrollableChart baseDate.add(Calendar.DAY_OF_YEAR, -nDays); baseDate.add(Calendar.DAY_OF_YEAR, -todayPositionInColumn); } - - public interface Controller - { - default void onToggleCheckmark(Timestamp timestamp, int value) {} - } } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 5f9b49f65..394108299 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -21,85 +21,94 @@ package org.isoron.uhabits.activities.habits.show import android.content.* import android.os.* import android.view.* -import android.widget.* import androidx.appcompat.app.* import kotlinx.coroutines.* +import org.isoron.androidbase.* import org.isoron.uhabits.* import org.isoron.uhabits.activities.* import org.isoron.uhabits.activities.common.dialogs.* -import org.isoron.uhabits.activities.habits.show.views.* import org.isoron.uhabits.core.commands.* -import org.isoron.uhabits.core.models.* -import org.isoron.uhabits.core.preferences.* -import org.isoron.uhabits.databinding.* -import org.isoron.uhabits.utils.* -import org.isoron.uhabits.widgets.* +import org.isoron.uhabits.core.ui.screens.habits.show.* +import org.isoron.uhabits.intents.* class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { - private lateinit var habit: Habit private lateinit var commandRunner: CommandRunner - private lateinit var preferences: Preferences + private lateinit var menu: ShowHabitMenu private lateinit var presenter: ShowHabitPresenter private lateinit var view: ShowHabitView - private lateinit var widgetUpdater: WidgetUpdater private val scope = CoroutineScope(Dispatchers.Main) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val appComponent = (applicationContext as HabitsApplication).component val habitList = appComponent.habitList - habit = habitList.getById(ContentUris.parseId(intent.data!!))!! - preferences = appComponent.preferences + val habit = habitList.getById(ContentUris.parseId(intent.data!!))!! + val preferences = appComponent.preferences commandRunner = appComponent.commandRunner - widgetUpdater = appComponent.widgetUpdater AndroidThemeSwitcher(this, preferences).apply() view = ShowHabitView(this) presenter = ShowHabitPresenter( - habit = habit, context = this, - preferences = appComponent.preferences + habit = habit, + preferences = appComponent.preferences, ) - view.onScoreCardSpinnerPosition = { position -> - preferences.scoreCardSpinnerPosition = position - updateWidgets() - updateViews() - } + val screen = ShowHabitScreen( + activity = this, + confirmDeleteDialogFactory = ConfirmDeleteDialogFactory { this }, + habit = habit, + intentFactory = IntentFactory(), + numberPickerFactory = NumberPickerFactory(this), + widgetUpdater = appComponent.widgetUpdater, + ) - view.onBarCardBoolSpinnerPosition = { position -> - preferences.barCardBoolSpinnerPosition = position - updateViews() - updateWidgets() - } + val behavior = ShowHabitBehavior( + commandRunner = commandRunner, + habit = habit, + habitList = habitList, + preferences = preferences, + screen = screen, + ) - view.onBarCardNumericalSpinnerPosition = { position -> - preferences.barCardNumericalSpinnerPosition = position - updateViews() - updateWidgets() - } + val menuBehavior = ShowHabitMenuBehavior( + commandRunner = commandRunner, + habit = habit, + habitList = habitList, + screen = screen, + system = HabitsDirFinder(AndroidDirFinder(this)), + taskRunner = appComponent.taskRunner, + ) - view.onClickEditHistoryButton = { - val dialog = HistoryEditorDialog() - dialog.setHabit(habit) - dialog.setController(object : HistoryEditorDialog.Controller { - }) - dialog.show(getSupportFragmentManager(), "historyEditor") - } + menu = ShowHabitMenu( + activity = this, + behavior = menuBehavior, + preferences = preferences, + ) + + view.onScoreCardSpinnerPosition = behavior::onScoreCardSpinnerPosition + view.onBarCardBoolSpinnerPosition = behavior::onBarCardBoolSpinnerPosition + view.onBarCardNumericalSpinnerPosition = behavior::onBarCardNumericalSpinnerPosition + view.onClickEditHistoryButton = behavior::onClickEditHistory setContentView(view) } - private fun updateWidgets() { - widgetUpdater.updateWidgets(habit.id) + override fun onCreateOptionsMenu(m: Menu): Boolean { + return menu.onCreateOptionsMenu(m) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return menu.onOptionsItemSelected(item) } override fun onResume() { super.onResume() commandRunner.addListener(this) - updateViews() + refresh() } override fun onPause() { @@ -108,108 +117,13 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { } override fun onCommandExecuted(command: Command?, refreshKey: Long?) { - updateViews() + refresh() } - private fun updateViews() { + fun refresh() { scope.launch { view.update(presenter.present()) } } } -data class ShowHabitViewModel( - val title: String = "", - val isNumerical: Boolean = false, - val color: PaletteColor = PaletteColor(1), - val subtitle: SubtitleCardViewModel, - val overview: OverviewCardViewModel, - val notes: NotesCardViewModel, - val target: TargetCardViewModel, - val streaks: StreakCardViewModel, - val scores: ScoreCardViewModel, - val frequency: FrequencyCardViewModel, - val history: HistoryCardViewModel, - val bar: BarCardViewModel, -) - -class ShowHabitView(context: Context) : FrameLayout(context) { - private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context)) - - var onScoreCardSpinnerPosition: (position: Int) -> Unit = {} - var onClickEditHistoryButton: () -> Unit = {} - var onBarCardBoolSpinnerPosition: (position: Int) -> Unit = {} - var onBarCardNumericalSpinnerPosition: (position: Int) -> Unit = {} - - init { - addView(binding.root) - binding.scoreCard.onSpinnerPosition = { onScoreCardSpinnerPosition(it) } - binding.historyCard.onClickEditButton = { onClickEditHistoryButton() } - binding.barCard.onBoolSpinnerPosition = { onBarCardBoolSpinnerPosition(it) } - binding.barCard.onNumericalSpinnerPosition = { onBarCardNumericalSpinnerPosition(it) } - } - - fun update(data: ShowHabitViewModel) { - setupToolbar(binding.toolbar, title = data.title, color = data.color) - binding.subtitleCard.update(data.subtitle) - binding.overviewCard.update(data.overview) - binding.notesCard.update(data.notes) - binding.targetCard.update(data.target) - binding.streakCard.update(data.streaks) - binding.scoreCard.update(data.scores) - binding.frequencyCard.update(data.frequency) - binding.historyCard.update(data.history) - binding.barCard.update(data.bar) - if (data.isNumerical) { - binding.overviewCard.visibility = GONE - binding.streakCard.visibility = GONE - } else { - binding.targetCard.visibility = GONE - } - } -} - -class ShowHabitPresenter( - val habit: Habit, - val context: Context, - val preferences: Preferences, -) { - private val subtitleCardPresenter = SubtitleCardPresenter(habit, context) - private val overviewCardPresenter = OverviewCardPresenter(habit) - private val notesCardPresenter = NotesCardPresenter(habit) - private val targetCardPresenter = TargetCardPresenter(habit = habit, - firstWeekday = preferences.firstWeekday, - resources = context.resources) - private val streakCartPresenter = StreakCartPresenter(habit) - private val scoreCardPresenter = ScoreCardPresenter(habit = habit, - firstWeekday = preferences.firstWeekday) - private val frequencyCardPresenter = FrequencyCardPresenter(habit = habit, - firstWeekday = preferences.firstWeekday) - private val historyCardViewModel = HistoryCardPresenter(habit = habit, - firstWeekday = preferences.firstWeekday, - isSkipEnabled = preferences.isSkipEnabled) - private val barCardPresenter = BarCardPresenter(habit = habit, - firstWeekday = preferences.firstWeekday) - - suspend fun present(): ShowHabitViewModel { - return ShowHabitViewModel( - title = habit.name, - color = habit.color, - isNumerical = habit.isNumerical, - subtitle = subtitleCardPresenter.present(), - overview = overviewCardPresenter.present(), - notes = notesCardPresenter.present(), - target = targetCardPresenter.present(), - streaks = streakCartPresenter.present(), - scores = scoreCardPresenter.present( - spinnerPosition = preferences.scoreCardSpinnerPosition - ), - frequency = frequencyCardPresenter.present(), - history = historyCardViewModel.present(), - bar = barCardPresenter.present( - boolSpinnerPosition = preferences.barCardBoolSpinnerPosition, - numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition, - ), - ) - } -} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt new file mode 100644 index 000000000..6f2db1c08 --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.show + +import android.view.* +import org.isoron.uhabits.* +import org.isoron.uhabits.core.preferences.* +import org.isoron.uhabits.core.ui.screens.habits.show.* + +class ShowHabitMenu( + val activity: ShowHabitActivity, + val behavior: ShowHabitMenuBehavior, + val preferences: Preferences, +) { + fun onCreateOptionsMenu(menu: Menu): Boolean { + activity.menuInflater.inflate(R.menu.show_habit, menu) + if (preferences.isDeveloper) { + menu.findItem(R.id.action_randomize).isVisible = true + } + return true + } + + fun onOptionsItemSelected(item: MenuItem): Boolean { + when(item.itemId) { + R.id.action_edit_habit -> { + behavior.onEditHabit() + return true + } + R.id.action_delete -> { + behavior.onDeleteHabit() + return true + } + R.id.action_randomize -> { + behavior.onRandomize() + return true + } + R.id.export -> { + behavior.onExportCSV() + return true + } + } + return false + } +} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java deleted file mode 100644 index 995438aff..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.habits.show; - -import android.content.*; - -import androidx.annotation.NonNull; - -import org.isoron.androidbase.activities.*; -import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.common.dialogs.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.ui.callbacks.*; -import org.isoron.uhabits.core.ui.screens.habits.list.*; -import org.isoron.uhabits.core.ui.screens.habits.show.*; -import org.isoron.uhabits.intents.*; - -import javax.inject.*; - -import dagger.*; - -@ActivityScope -public class ShowHabitScreen extends BaseScreen - implements ShowHabitMenuBehavior.Screen, - ShowHabitBehavior.Screen, - HistoryEditorDialog.Controller - //ShowHabitRootView.Controller -{ - @NonNull - private final Habit habit; - - @NonNull - private final ConfirmDeleteDialogFactory confirmDeleteDialogFactory; - - private final Lazy behavior; - - @NonNull - private final IntentFactory intentFactory; - - @NonNull - private final NumberPickerFactory numberPickerFactory; - - @Inject - public ShowHabitScreen(@NonNull BaseActivity activity, - @NonNull Habit habit, - //@NonNull ShowHabitRootView view, - @NonNull ShowHabitsMenu menu, - @NonNull ConfirmDeleteDialogFactory confirmDeleteDialogFactory, - @NonNull IntentFactory intentFactory, - @NonNull NumberPickerFactory numberPickerFactory, - @NonNull Lazy behavior) - { - super(activity); - this.intentFactory = intentFactory; - setMenu(menu); - //setRootView(view); - - this.habit = habit; - this.behavior = behavior; - this.confirmDeleteDialogFactory = confirmDeleteDialogFactory; - this.numberPickerFactory = numberPickerFactory; - //view.setController(this); - } - -// @Override -// public void onEditHistoryButtonClick() -// { -// behavior.get().onEditHistory(); -// } - - @Override - public void showNumberPicker(double value, - @NonNull String unit, - @NonNull ListHabitsBehavior.NumberPickerCallback callback) - { - numberPickerFactory.create(value, unit, callback).show(); - } - - @Override - public void onToggleCheckmark(Timestamp timestamp, int value) - { - behavior.get().onToggleCheckmark(timestamp, value); - } - -// @Override -// public void onToolbarChanged() -// { -// invalidateToolbar(); -// } - - @Override - public void reattachDialogs() - { - super.reattachDialogs(); - HistoryEditorDialog historyEditor = (HistoryEditorDialog) activity - .getSupportFragmentManager() - .findFragmentByTag("historyEditor"); - if (historyEditor != null) historyEditor.setController(this); - } - - @Override - public void showEditHabitScreen(@NonNull Habit habit) - { - Intent intent = intentFactory.startEditActivity(activity, habit); - activity.startActivity(intent); - } - - @Override - public void showEditHistoryScreen() - { - HistoryEditorDialog dialog = new HistoryEditorDialog(); - dialog.setHabit(habit); - dialog.setController(this); - dialog.show(activity.getSupportFragmentManager(), "historyEditor"); - } - - @Override - public void showMessage(ShowHabitMenuBehavior.Message m) - { - switch (m) - { - case COULD_NOT_EXPORT: - showMessage(R.string.could_not_export); - - case HABIT_DELETED: - showMessage(R.string.delete_habits_message); - } - } - - @Override - public void showDeleteConfirmationScreen(@NonNull OnConfirmedCallback callback) { - activity.showDialog(confirmDeleteDialogFactory.create(callback)); - } - - @Override - public void close() { - activity.finish(); - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.kt new file mode 100644 index 000000000..4da610ad6 --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitScreen.kt @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.show + +import org.isoron.uhabits.activities.common.dialogs.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.ui.callbacks.* +import org.isoron.uhabits.core.ui.screens.habits.list.* +import org.isoron.uhabits.core.ui.screens.habits.show.* +import org.isoron.uhabits.intents.* +import org.isoron.uhabits.utils.* +import org.isoron.uhabits.widgets.* + + +class ShowHabitScreen( + val activity: ShowHabitActivity, + val confirmDeleteDialogFactory: ConfirmDeleteDialogFactory, + val habit: Habit, + val intentFactory: IntentFactory, + val numberPickerFactory: NumberPickerFactory, + val widgetUpdater: WidgetUpdater, +) : ShowHabitBehavior.Screen, ShowHabitMenuBehavior.Screen { + + override fun showNumberPicker(value: Double, unit: String, callback: ListHabitsBehavior.NumberPickerCallback) { + numberPickerFactory.create(value, unit, callback).show(); + } + + override fun updateWidgets() { + widgetUpdater.updateWidgets(habit.id) + } + + override fun refresh() { + activity.refresh() + } + + override fun showHistoryEditorDialog(listener: OnToggleCheckmarkListener) { + val dialog = HistoryEditorDialog() + dialog.setHabit(habit) + dialog.setOnToggleCheckmarkListener(listener) + dialog.show(activity.supportFragmentManager, "historyEditor") + } + + override fun showEditHabitScreen(habit: Habit) { + activity.startActivity(intentFactory.startEditActivity(activity, habit)) + } + + override fun showMessage(m: ShowHabitMenuBehavior.Message?) { + when (m) { + ShowHabitMenuBehavior.Message.COULD_NOT_EXPORT -> { + activity.showMessage(org.isoron.uhabits.R.string.could_not_export) + } + } + } + + override fun showSendFileScreen(filename: String) { + activity.showSendFileScreen(filename) + } + + override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback) { + confirmDeleteDialogFactory.create(callback).show() + } + + override fun close() { + activity.finish() + } +} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt new file mode 100644 index 000000000..9abb76a5d --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.activities.habits.show + +import android.content.* +import android.view.* +import android.widget.* +import org.isoron.uhabits.activities.habits.show.views.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.preferences.* +import org.isoron.uhabits.databinding.* +import org.isoron.uhabits.utils.* + +data class ShowHabitViewModel( + val title: String = "", + val isNumerical: Boolean = false, + val color: PaletteColor = PaletteColor(1), + val subtitle: SubtitleCardViewModel, + val overview: OverviewCardViewModel, + val notes: NotesCardViewModel, + val target: TargetCardViewModel, + val streaks: StreakCardViewModel, + val scores: ScoreCardViewModel, + val frequency: FrequencyCardViewModel, + val history: HistoryCardViewModel, + val bar: BarCardViewModel, +) + +class ShowHabitView(context: Context) : FrameLayout(context) { + private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context)) + + var onScoreCardSpinnerPosition: (position: Int) -> Unit = {} + var onClickEditHistoryButton: () -> Unit = {} + var onBarCardBoolSpinnerPosition: (position: Int) -> Unit = {} + var onBarCardNumericalSpinnerPosition: (position: Int) -> Unit = {} + + init { + addView(binding.root) + binding.scoreCard.onSpinnerPosition = { onScoreCardSpinnerPosition(it) } + binding.historyCard.onClickEditButton = { onClickEditHistoryButton() } + binding.barCard.onBoolSpinnerPosition = { onBarCardBoolSpinnerPosition(it) } + binding.barCard.onNumericalSpinnerPosition = { onBarCardNumericalSpinnerPosition(it) } + } + + fun update(data: ShowHabitViewModel) { + setupToolbar(binding.toolbar, title = data.title, color = data.color) + binding.subtitleCard.update(data.subtitle) + binding.overviewCard.update(data.overview) + binding.notesCard.update(data.notes) + binding.targetCard.update(data.target) + binding.streakCard.update(data.streaks) + binding.scoreCard.update(data.scores) + binding.frequencyCard.update(data.frequency) + binding.historyCard.update(data.history) + binding.barCard.update(data.bar) + if (data.isNumerical) { + binding.overviewCard.visibility = GONE + binding.streakCard.visibility = GONE + } else { + binding.targetCard.visibility = GONE + } + } +} + +class ShowHabitPresenter( + val habit: Habit, + val context: Context, + val preferences: Preferences, +) { + private val subtitleCardPresenter = SubtitleCardPresenter(habit, context) + private val overviewCardPresenter = OverviewCardPresenter(habit) + private val notesCardPresenter = NotesCardPresenter(habit) + private val targetCardPresenter = TargetCardPresenter( + habit = habit, + firstWeekday = preferences.firstWeekday, + resources = context.resources, + ) + private val streakCartPresenter = StreakCartPresenter(habit) + private val scoreCardPresenter = ScoreCardPresenter( + habit = habit, + firstWeekday = preferences.firstWeekday, + ) + private val frequencyCardPresenter = FrequencyCardPresenter( + habit = habit, + firstWeekday = preferences.firstWeekday, + ) + private val historyCardViewModel = HistoryCardPresenter( + habit = habit, + firstWeekday = preferences.firstWeekday, + isSkipEnabled = preferences.isSkipEnabled, + ) + private val barCardPresenter = BarCardPresenter( + habit = habit, + firstWeekday = preferences.firstWeekday, + ) + + suspend fun present(): ShowHabitViewModel { + return ShowHabitViewModel( + title = habit.name, + color = habit.color, + isNumerical = habit.isNumerical, + subtitle = subtitleCardPresenter.present(), + overview = overviewCardPresenter.present(), + notes = notesCardPresenter.present(), + target = targetCardPresenter.present(), + streaks = streakCartPresenter.present(), + scores = scoreCardPresenter.present( + spinnerPosition = preferences.scoreCardSpinnerPosition + ), + frequency = frequencyCardPresenter.present(), + history = historyCardViewModel.present(), + bar = barCardPresenter.present( + boolSpinnerPosition = preferences.barCardBoolSpinnerPosition, + numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition, + ), + ) + } +} \ No newline at end of file diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java deleted file mode 100644 index 76eca4357..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitsMenu.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2016 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.habits.show; - -import android.view.*; - -import androidx.annotation.NonNull; - -import org.isoron.androidbase.activities.*; -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.preferences.Preferences; -import org.isoron.uhabits.core.ui.screens.habits.show.*; - -import javax.inject.*; - -import dagger.*; - -@ActivityScope -public class ShowHabitsMenu extends BaseMenu -{ -// @NonNull -// private Lazy behavior; - - @NonNull - private final Preferences prefs; - - @Inject - public ShowHabitsMenu(@NonNull BaseActivity activity, - //@NonNull Lazy behavior, - @NonNull Preferences prefs) - { - super(activity); - //this.behavior = behavior; - this.prefs = prefs; - } - - @Override - public void onCreate(@NonNull Menu menu) - { - super.onCreate(menu); - - if (prefs.isDeveloper()) - menu.findItem(R.id.action_randomize).setVisible(true); - } - - @Override - public boolean onItemSelected(@NonNull MenuItem item) - { - switch (item.getItemId()) - { -// case R.id.action_edit_habit: -// behavior.get().onEditHabit(); -// return true; -// -// case R.id.export: -// behavior.get().onExportCSV(); -// return true; -// -// case R.id.action_delete: -// behavior.get().onDeleteHabit(); -// return true; -// -// case R.id.action_randomize: -// behavior.get().onRandomize(); -// return true; - - default: - return false; - } - } - - @Override - protected int getMenuResourceId() - { - return R.menu.show_habit; - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index 0c56165b3..828cac545 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -19,6 +19,8 @@ package org.isoron.uhabits.utils +import android.app.* +import android.content.* import android.graphics.* import android.graphics.drawable.* import android.view.* @@ -28,10 +30,12 @@ import android.widget.RelativeLayout.* import androidx.annotation.* import androidx.appcompat.app.* import androidx.appcompat.widget.Toolbar +import androidx.core.content.* import com.google.android.material.snackbar.* import org.isoron.androidbase.utils.* import org.isoron.uhabits.* import org.isoron.uhabits.core.models.* +import java.io.* fun RelativeLayout.addBelow(view: View, subject: View, @@ -86,6 +90,21 @@ fun View.showMessage(@StringRes stringId: Int) { } } +fun Activity.showMessage(@StringRes stringId: Int) { + this.findViewById(android.R.id.content).showMessage(stringId) +} + +fun Activity.showSendFileScreen(archiveFilename: String) { + val file = File(archiveFilename) + val fileUri = FileProvider.getUriForFile(this, "org.isoron.uhabits", file) + this.startActivity(Intent().apply { + action = Intent.ACTION_SEND + type = "application/zip" + putExtra(Intent.EXTRA_STREAM, fileUri) + flags = Intent.FLAG_GRANT_READ_URI_PERMISSION + }) +} + fun View.setupToolbar(toolbar: Toolbar, title: String, color: PaletteColor) { toolbar.elevation = InterfaceUtils.dpToPixels(context, 2f) val res = StyledResources(context) diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/callbacks/OnToggleCheckmarkListener.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/callbacks/OnToggleCheckmarkListener.kt new file mode 100644 index 000000000..874a6b407 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/callbacks/OnToggleCheckmarkListener.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2016-2020 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +package org.isoron.uhabits.core.ui.callbacks + +import org.isoron.uhabits.core.models.* + +interface OnToggleCheckmarkListener { + fun onToggleCheckmark(timestamp: Timestamp, value: Int) {} +} \ No newline at end of file diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java deleted file mode 100644 index 3f81dfeb2..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.ui.screens.habits.show; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.ui.screens.habits.list.*; - -import javax.inject.*; - -public class ShowHabitBehavior -{ - private HabitList habitList; - - @NonNull - private final Habit habit; - - @NonNull - private final CommandRunner commandRunner; - - @NonNull - private Screen screen; - - @Inject - public ShowHabitBehavior(@NonNull HabitList habitList, - @NonNull CommandRunner commandRunner, - @NonNull Habit habit, - @NonNull Screen screen) - { - this.habitList = habitList; - this.habit = habit; - this.commandRunner = commandRunner; - this.screen = screen; - } - - public void onEditHistory() - { - screen.showEditHistoryScreen(); - } - - public void onToggleCheckmark(Timestamp timestamp, int value) - { - if (habit.isNumerical()) { - CheckmarkList checkmarks = habit.getCheckmarks(); - double oldValue = checkmarks.getValues(timestamp, timestamp)[0]; - - screen.showNumberPicker(oldValue / 1000, habit.getUnit(), newValue -> - { - newValue = Math.round(newValue * 1000); - commandRunner.execute( - new CreateRepetitionCommand(habitList, habit, timestamp, (int) newValue), - habit.getId()); - }); - } else { - commandRunner.execute( - new CreateRepetitionCommand(habitList, habit, timestamp, value), null); - } - } - - public interface Screen - { - void showEditHistoryScreen(); - - void showNumberPicker(double value, - @NonNull String unit, - @NonNull ListHabitsBehavior.NumberPickerCallback callback); - } -} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.kt new file mode 100644 index 000000000..e248f8742 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitBehavior.kt @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.ui.screens.habits.show + +import org.isoron.uhabits.core.commands.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.preferences.* +import org.isoron.uhabits.core.ui.callbacks.* +import org.isoron.uhabits.core.ui.screens.habits.list.* + +class ShowHabitBehavior( + private val habitList: HabitList, + private val commandRunner: CommandRunner, + private val habit: Habit, + private val screen: Screen, + private val preferences: Preferences, +) : OnToggleCheckmarkListener { + + fun onScoreCardSpinnerPosition(position: Int) { + preferences.scoreCardSpinnerPosition = position + screen.updateWidgets() + screen.refresh() + } + + fun onBarCardBoolSpinnerPosition(position: Int) { + preferences.barCardBoolSpinnerPosition = position + screen.updateWidgets() + screen.refresh() + } + + fun onBarCardNumericalSpinnerPosition(position: Int) { + preferences.barCardNumericalSpinnerPosition = position + screen.refresh() + screen.updateWidgets() + } + + fun onClickEditHistory() { + screen.showHistoryEditorDialog(this) + } + + override fun onToggleCheckmark(timestamp: Timestamp, value: Int) { + if (habit.isNumerical) { + val checkmarks = habit.checkmarks + val oldValue = checkmarks.getValues(timestamp, timestamp)[0].toDouble() + screen.showNumberPicker(oldValue / 1000, habit.unit) { newValue: Double -> + val thousands = Math.round(newValue * 1000).toInt() + commandRunner.execute( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + thousands, + ), + habit.getId(), + ) + } + } else { + commandRunner.execute( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + value, + ), + null, + ) + } + } + + interface Screen { + fun showNumberPicker(value: Double, + unit: String, + callback: ListHabitsBehavior.NumberPickerCallback) + + fun updateWidgets() + fun refresh() + fun showHistoryEditorDialog(listener: OnToggleCheckmarkListener) + } +} \ No newline at end of file diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java deleted file mode 100644 index 2c5599c90..000000000 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2017 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.core.ui.screens.habits.show; - -import androidx.annotation.*; - -import org.isoron.uhabits.core.commands.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.tasks.*; -import org.isoron.uhabits.core.ui.callbacks.*; -import org.isoron.uhabits.core.utils.*; - -import java.io.*; -import java.util.*; - -import javax.inject.*; - -import static java.lang.Math.*; - - -public class ShowHabitMenuBehavior -{ - private HabitList habitList; - - @NonNull - private final Habit habit; - - @NonNull - private final TaskRunner taskRunner; - - @NonNull - private Screen screen; - - @NonNull - private System system; - - @NonNull - private CommandRunner commandRunner; - - @Inject - public ShowHabitMenuBehavior(@NonNull HabitList habitList, - @NonNull Habit habit, - @NonNull TaskRunner taskRunner, - @NonNull Screen screen, - @NonNull System system, - @NonNull CommandRunner commandRunner) - { - this.habitList = habitList; - this.habit = habit; - this.taskRunner = taskRunner; - this.screen = screen; - this.system = system; - this.commandRunner = commandRunner; - } - - public void onEditHabit() - { - screen.showEditHabitScreen(habit); - } - - public void onExportCSV() - { - List selected = Collections.singletonList(habit); - File outputDir = system.getCSVOutputDir(); - - taskRunner.execute( - new ExportCSVTask(habitList, selected, outputDir, filename -> - { - if (filename != null) screen.showSendFileScreen(filename); - else screen.showMessage(Message.COULD_NOT_EXPORT); - })); - } - - public void onDeleteHabit() - { - List selected = Collections.singletonList(habit); - - screen.showDeleteConfirmationScreen(() -> { - commandRunner.execute(new DeleteHabitsCommand(habitList, selected), - null); - screen.close(); - }); - } - - public void onRandomize() - { - Random random = new Random(); - habit.getRepetitions().removeAll(); - double strength = 50; - - for (int i = 0; i < 365 * 5; i++) - { - if (i % 7 == 0) strength = max(0, min(100, strength + 10 * random.nextGaussian())); - if (random.nextInt(100) > strength) continue; - - int value = Checkmark.YES_MANUAL; - if (habit.isNumerical()) - value = (int) (1000 + 250 * random.nextGaussian() * strength / 100) * 1000; - - habit.getRepetitions().setValue(DateUtils.getToday().minus(i), value); - } - - habit.invalidateNewerThan(Timestamp.ZERO); - } - - public enum Message - { - COULD_NOT_EXPORT, HABIT_DELETED - } - - public interface Screen - { - void showEditHabitScreen(@NonNull Habit habit); - - void showMessage(Message m); - - void showSendFileScreen(String filename); - - void showDeleteConfirmationScreen( - @NonNull OnConfirmedCallback callback); - - void close(); - } - - public interface System - { - File getCSVOutputDir(); - } -} diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.kt new file mode 100644 index 000000000..8deb18189 --- /dev/null +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehavior.kt @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 Álinson Santos Xavier + * + * This file is part of Loop Habit Tracker. + * + * Loop Habit Tracker is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * Loop Habit Tracker is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ +package org.isoron.uhabits.core.ui.screens.habits.show + +import org.isoron.uhabits.core.commands.* +import org.isoron.uhabits.core.models.* +import org.isoron.uhabits.core.tasks.* +import org.isoron.uhabits.core.ui.callbacks.* +import org.isoron.uhabits.core.utils.* +import java.io.* +import java.util.* + +class ShowHabitMenuBehavior( + private val commandRunner: CommandRunner, + private val habit: Habit, + private val habitList: HabitList, + private val screen: Screen, + private val system: System, + private val taskRunner: TaskRunner, +) { + fun onEditHabit() { + screen.showEditHabitScreen(habit) + } + + fun onExportCSV() { + val outputDir = system.getCSVOutputDir() + taskRunner.execute(ExportCSVTask(habitList, listOf(habit), outputDir) { filename: String? -> + if (filename != null) { + screen.showSendFileScreen(filename) + } else { + screen.showMessage(Message.COULD_NOT_EXPORT) + } + }) + } + + fun onDeleteHabit() { + screen.showDeleteConfirmationScreen { + commandRunner.execute(DeleteHabitsCommand(habitList, listOf(habit)), null) + screen.close() + } + } + + fun onRandomize() { + val random = Random() + habit.repetitions.removeAll() + var strength = 50.0 + for (i in 0 until 365 * 5) { + if (i % 7 == 0) strength = Math.max(0.0, Math.min(100.0, strength + 10 * random.nextGaussian())) + if (random.nextInt(100) > strength) continue + var value = Checkmark.YES_MANUAL + if (habit.isNumerical) value = (1000 + 250 * random.nextGaussian() * strength / 100).toInt() * 1000 + habit.repetitions.setValue(DateUtils.getToday().minus(i), value) + } + habit.invalidateNewerThan(Timestamp.ZERO) + screen.refresh() + } + + enum class Message { + COULD_NOT_EXPORT + } + + interface Screen { + fun showEditHabitScreen(habit: Habit) + fun showMessage(m: Message?) + fun showSendFileScreen(filename: String) + fun showDeleteConfirmationScreen( + callback: OnConfirmedCallback) + fun close() + fun refresh() + } + + interface System { + fun getCSVOutputDir(): File + } +} \ No newline at end of file diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehaviorTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehaviorTest.java index fefade28e..efb48e927 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehaviorTest.java +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabitMenuBehaviorTest.java @@ -49,8 +49,7 @@ public class ShowHabitMenuBehaviorTest extends BaseUnitTest screen = mock(ShowHabitMenuBehavior.Screen.class); habit = fixtures.createShortHabit(); - menu = new ShowHabitMenuBehavior(habitList, habit, taskRunner, screen, - system, commandRunner); + menu = new ShowHabitMenuBehavior(commandRunner, habit, habitList, screen, system, taskRunner); } @Test