mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 17:18:52 -06:00
HistoryChart: Fix HistoryEditorDialog
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 33 KiB |
@@ -177,4 +177,8 @@ class AndroidCanvas : Canvas {
|
||||
val bmp = innerBitmap ?: throw UnsupportedOperationException()
|
||||
return AndroidImage(bmp)
|
||||
}
|
||||
|
||||
override fun measureText(text: String): Double {
|
||||
return textPaint.measureText(text) / innerDensity
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,24 @@ class AndroidDataView(
|
||||
override fun onTouchEvent(event: MotionEvent?) = detector.onTouchEvent(event)
|
||||
override fun onDown(e: MotionEvent?) = true
|
||||
override fun onShowPress(e: MotionEvent?) = Unit
|
||||
override fun onSingleTapUp(e: MotionEvent?) = false
|
||||
|
||||
override fun onSingleTapUp(e: MotionEvent?): Boolean {
|
||||
val x: Float
|
||||
val y: Float
|
||||
try {
|
||||
val pointerId = e!!.getPointerId(0)
|
||||
x = e.getX(pointerId)
|
||||
y = e.getY(pointerId)
|
||||
} catch (ex: RuntimeException) {
|
||||
// Android often throws IllegalArgumentException here. Apparently,
|
||||
// the pointer id may become invalid shortly after calling
|
||||
// e.getPointerId.
|
||||
return false
|
||||
}
|
||||
view?.onClick(x / canvas.innerDensity, y / canvas.innerDensity)
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onLongPress(e: MotionEvent?) = Unit
|
||||
|
||||
override fun onScroll(
|
||||
@@ -76,7 +93,16 @@ class AndroidDataView(
|
||||
velocityX: Float,
|
||||
velocityY: Float,
|
||||
): Boolean {
|
||||
scroller.fling(scroller.currX, scroller.currY, velocityX.toInt() / 2, 0, 0, 10000, 0, 0)
|
||||
scroller.fling(
|
||||
scroller.currX,
|
||||
scroller.currY,
|
||||
velocityX.toInt() / 2,
|
||||
0,
|
||||
0,
|
||||
Integer.MAX_VALUE,
|
||||
0,
|
||||
0
|
||||
)
|
||||
invalidate()
|
||||
scrollAnimator.duration = scroller.duration.toLong()
|
||||
scrollAnimator.start()
|
||||
@@ -99,11 +125,14 @@ class AndroidDataView(
|
||||
}
|
||||
|
||||
private fun updateDataOffset() {
|
||||
var newDataOffset: Int = scroller.currX / (view.dataColumnWidth * canvas.innerDensity).toInt()
|
||||
newDataOffset = Math.max(0, newDataOffset)
|
||||
if (newDataOffset != view.dataOffset) {
|
||||
view.dataOffset = newDataOffset
|
||||
postInvalidate()
|
||||
view?.let { v ->
|
||||
var newDataOffset: Int =
|
||||
scroller.currX / (v.dataColumnWidth * canvas.innerDensity).toInt()
|
||||
newDataOffset = Math.max(0, newDataOffset)
|
||||
if (newDataOffset != v.dataOffset) {
|
||||
v.dataOffset = newDataOffset
|
||||
postInvalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ open class AndroidView<T : View>(
|
||||
attrs: AttributeSet? = null,
|
||||
) : android.view.View(context, attrs) {
|
||||
|
||||
lateinit var view: T
|
||||
var view: T? = null
|
||||
val canvas = AndroidCanvas()
|
||||
|
||||
override fun onDraw(canvas: android.graphics.Canvas) {
|
||||
@@ -36,6 +36,6 @@ open class AndroidView<T : View>(
|
||||
this.canvas.innerWidth = width
|
||||
this.canvas.innerHeight = height
|
||||
this.canvas.innerDensity = resources.displayMetrics.density.toDouble()
|
||||
view.draw(this.canvas)
|
||||
view?.draw(this.canvas)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.isoron.uhabits.activities.common.dialogs;
|
||||
|
||||
import android.app.*;
|
||||
import android.content.*;
|
||||
import android.os.*;
|
||||
import android.util.*;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.*;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.*;
|
||||
|
||||
import org.isoron.uhabits.*;
|
||||
import org.isoron.uhabits.core.commands.*;
|
||||
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.core.ui.screens.habits.show.views.*;
|
||||
import org.isoron.uhabits.core.ui.views.*;
|
||||
import org.isoron.uhabits.utils.*;
|
||||
import org.jetbrains.annotations.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class HistoryEditorDialog extends AppCompatDialogFragment
|
||||
implements DialogInterface.OnClickListener, CommandRunner.Listener
|
||||
{
|
||||
@Nullable
|
||||
private Habit habit;
|
||||
|
||||
@Nullable
|
||||
HistoryChart historyChart;
|
||||
|
||||
@NonNull
|
||||
private OnToggleCheckmarkListener onToggleCheckmarkListener;
|
||||
|
||||
private HabitList habitList;
|
||||
|
||||
private TaskRunner taskRunner;
|
||||
|
||||
private Preferences prefs;
|
||||
|
||||
private CommandRunner commandRunner;
|
||||
|
||||
public HistoryEditorDialog()
|
||||
{
|
||||
this.onToggleCheckmarkListener = new OnToggleCheckmarkListener()
|
||||
{
|
||||
@Override
|
||||
public void onToggleEntry(@NotNull Timestamp timestamp, int value)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which)
|
||||
{
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState)
|
||||
{
|
||||
Context context = getActivity();
|
||||
|
||||
HabitsApplication app =
|
||||
(HabitsApplication) getActivity().getApplicationContext();
|
||||
habitList = app.getComponent().getHabitList();
|
||||
taskRunner = app.getComponent().getTaskRunner();
|
||||
commandRunner = app.getComponent().getCommandRunner();
|
||||
prefs = app.getComponent().getPreferences();
|
||||
|
||||
// historyChart = new HistoryChart(context);
|
||||
// historyChart.setOnToggleCheckmarkListener(onToggleCheckmarkListener);
|
||||
// historyChart.setFirstWeekday(prefs.getFirstWeekday());
|
||||
// historyChart.setSkipEnabled(prefs.isSkipEnabled());
|
||||
|
||||
// if (savedInstanceState != null)
|
||||
// {
|
||||
// long id = savedInstanceState.getLong("habit", -1);
|
||||
// if (id > 0) this.habit = habitList.getById(id);
|
||||
// historyChart.onRestoreInstanceState(
|
||||
// savedInstanceState.getParcelable("historyChart"));
|
||||
// }
|
||||
//
|
||||
// int padding =
|
||||
// (int) getDimension(getContext(), R.dimen.history_editor_padding);
|
||||
//
|
||||
// historyChart.setPadding(padding, 0, padding, 0);
|
||||
// historyChart.setIsEditable(true);
|
||||
//
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder
|
||||
.setTitle(R.string.history)
|
||||
// .setView(historyChart)
|
||||
.setPositiveButton(android.R.string.ok, this);
|
||||
//
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
|
||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
int maxHeight = getResources().getDimensionPixelSize(
|
||||
R.dimen.history_editor_max_height);
|
||||
int width = metrics.widthPixels;
|
||||
int height = Math.min(metrics.heightPixels, maxHeight);
|
||||
|
||||
getDialog().getWindow().setLayout(width, height);
|
||||
commandRunner.addListener(this);
|
||||
refreshData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
commandRunner.removeListener(this);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState)
|
||||
{
|
||||
// outState.putLong("habit", habit.getId());
|
||||
// outState.putParcelable("historyChart", historyChart.onSaveInstanceState());
|
||||
}
|
||||
|
||||
public void setOnToggleCheckmarkListener(@NonNull OnToggleCheckmarkListener onToggleCheckmarkListener)
|
||||
{
|
||||
this.onToggleCheckmarkListener = onToggleCheckmarkListener;
|
||||
}
|
||||
|
||||
public void setHabit(@Nullable Habit habit)
|
||||
{
|
||||
this.habit = habit;
|
||||
}
|
||||
|
||||
private void refreshData()
|
||||
{
|
||||
if (habit == null) return;
|
||||
taskRunner.execute(new RefreshTask());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCommandFinished(@NonNull Command command)
|
||||
{
|
||||
refreshData();
|
||||
}
|
||||
|
||||
private class RefreshTask implements Task
|
||||
{
|
||||
public List<HistoryChart.Square> checkmarks;
|
||||
|
||||
@Override
|
||||
public void doInBackground()
|
||||
{
|
||||
HistoryCardViewModel model = new HistoryCardPresenter().present(
|
||||
habit,
|
||||
prefs.getFirstWeekday(),
|
||||
prefs.isSkipEnabled(),
|
||||
new LightTheme()
|
||||
);
|
||||
checkmarks = model.getSeries();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostExecute()
|
||||
{
|
||||
if (getContext() == null || habit == null || historyChart == null)
|
||||
return;
|
||||
|
||||
int color = PaletteUtilsKt.toThemedAndroidColor(habit.getColor(), getContext());
|
||||
// historyChart.setColor(color);
|
||||
// historyChart.setEntries(checkmarks);
|
||||
// historyChart.setNumerical(habit.isNumerical());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.isoron.uhabits.activities.common.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import org.isoron.platform.gui.AndroidDataView
|
||||
import org.isoron.platform.time.JavaLocalDateFormatter
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.commands.Command
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.views.HistoryCardPresenter
|
||||
import org.isoron.uhabits.core.ui.views.HistoryChart
|
||||
import org.isoron.uhabits.core.ui.views.LightTheme
|
||||
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import java.util.Locale
|
||||
import kotlin.math.min
|
||||
|
||||
class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener {
|
||||
|
||||
private lateinit var commandRunner: CommandRunner
|
||||
private lateinit var habit: Habit
|
||||
private lateinit var preferences: Preferences
|
||||
private lateinit var dataView: AndroidDataView
|
||||
|
||||
private var chart: HistoryChart? = null
|
||||
private var onDateClickedListener: OnDateClickedListener? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val component = (activity!!.application as HabitsApplication).component
|
||||
commandRunner = component.commandRunner
|
||||
habit = component.habitList.getById(arguments!!.getLong("habit"))!!
|
||||
preferences = component.preferences
|
||||
|
||||
chart = HistoryChart(
|
||||
dateFormatter = JavaLocalDateFormatter(Locale.getDefault()),
|
||||
firstWeekday = preferences.firstWeekday,
|
||||
paletteColor = habit.color,
|
||||
series = emptyList(),
|
||||
theme = LightTheme(),
|
||||
today = DateUtils.getTodayWithOffset().toLocalDate(),
|
||||
onDateClickedListener = onDateClickedListener ?: OnDateClickedListener { },
|
||||
padding = 10.0,
|
||||
)
|
||||
dataView = AndroidDataView(context!!, null)
|
||||
dataView.view = chart!!
|
||||
|
||||
return Dialog(context!!).apply {
|
||||
val metrics = resources.displayMetrics
|
||||
val maxHeight = resources.getDimensionPixelSize(R.dimen.history_editor_max_height)
|
||||
setContentView(dataView)
|
||||
window!!.setLayout(metrics.widthPixels, min(metrics.heightPixels, maxHeight))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
commandRunner.addListener(this)
|
||||
refreshData()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
commandRunner.removeListener(this)
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
fun setOnDateClickedListener(listener: OnDateClickedListener) {
|
||||
onDateClickedListener = listener
|
||||
chart?.onDateClickedListener = listener
|
||||
}
|
||||
|
||||
private fun refreshData() {
|
||||
val model = HistoryCardPresenter().present(
|
||||
habit,
|
||||
preferences.firstWeekday,
|
||||
preferences.isSkipEnabled,
|
||||
theme = LightTheme()
|
||||
)
|
||||
chart?.series = model.series
|
||||
dataView.postInvalidate()
|
||||
}
|
||||
|
||||
override fun onCommandFinished(command: Command) {
|
||||
refreshData()
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.activities.AndroidThemeSwitcher
|
||||
import org.isoron.uhabits.activities.HabitsDirFinder
|
||||
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialogFactory
|
||||
import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
|
||||
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
||||
import org.isoron.uhabits.core.commands.Command
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
@@ -51,6 +52,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
private lateinit var habit: Habit
|
||||
private lateinit var preferences: Preferences
|
||||
private lateinit var themeSwitcher: AndroidThemeSwitcher
|
||||
private lateinit var behavior: ShowHabitBehavior
|
||||
|
||||
private val scope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
@@ -76,7 +78,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
widgetUpdater = appComponent.widgetUpdater,
|
||||
)
|
||||
|
||||
val behavior = ShowHabitBehavior(
|
||||
behavior = ShowHabitBehavior(
|
||||
commandRunner = commandRunner,
|
||||
habit = habit,
|
||||
habitList = habitList,
|
||||
@@ -118,6 +120,9 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
commandRunner.addListener(this)
|
||||
supportFragmentManager.findFragmentByTag("historyEditor")?.let {
|
||||
(it as HistoryEditorDialog).setOnDateClickedListener(behavior)
|
||||
}
|
||||
refresh()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,16 +19,18 @@
|
||||
|
||||
package org.isoron.uhabits.activities.habits.show
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.HapticFeedbackConstants
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialogFactory
|
||||
import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
|
||||
import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback
|
||||
import org.isoron.uhabits.core.ui.callbacks.OnToggleCheckmarkListener
|
||||
import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitBehavior
|
||||
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuBehavior
|
||||
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
|
||||
import org.isoron.uhabits.intents.IntentFactory
|
||||
import org.isoron.uhabits.utils.showMessage
|
||||
import org.isoron.uhabits.utils.showSendFileScreen
|
||||
@@ -43,7 +45,11 @@ class ShowHabitScreen(
|
||||
val widgetUpdater: WidgetUpdater,
|
||||
) : ShowHabitBehavior.Screen, ShowHabitMenuBehavior.Screen {
|
||||
|
||||
override fun showNumberPicker(value: Double, unit: String, callback: ListHabitsBehavior.NumberPickerCallback) {
|
||||
override fun showNumberPicker(
|
||||
value: Double,
|
||||
unit: String,
|
||||
callback: ListHabitsBehavior.NumberPickerCallback,
|
||||
) {
|
||||
numberPickerFactory.create(value, unit, callback).show()
|
||||
}
|
||||
|
||||
@@ -55,13 +61,19 @@ class ShowHabitScreen(
|
||||
activity.refresh()
|
||||
}
|
||||
|
||||
override fun showHistoryEditorDialog(listener: OnToggleCheckmarkListener) {
|
||||
override fun showHistoryEditorDialog(listener: OnDateClickedListener) {
|
||||
val dialog = HistoryEditorDialog()
|
||||
dialog.setHabit(habit)
|
||||
dialog.setOnToggleCheckmarkListener(listener)
|
||||
dialog.arguments = Bundle().apply {
|
||||
putLong("habit", habit.id!!)
|
||||
}
|
||||
dialog.setOnDateClickedListener(listener)
|
||||
dialog.show(activity.supportFragmentManager, "historyEditor")
|
||||
}
|
||||
|
||||
override fun touchFeedback() {
|
||||
activity.window.decorView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY)
|
||||
}
|
||||
|
||||
override fun showEditHabitScreen(habit: Habit) {
|
||||
activity.startActivity(intentFactory.startEditActivity(activity, habit))
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont
|
||||
}
|
||||
|
||||
fun update(data: HistoryCardViewModel) {
|
||||
|
||||
val androidColor = data.color.toThemedAndroidColor(context)
|
||||
binding.title.setTextColor(androidColor)
|
||||
binding.chart.view = HistoryChart(
|
||||
@@ -51,10 +50,6 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont
|
||||
series = data.series,
|
||||
firstWeekday = data.firstWeekday,
|
||||
)
|
||||
|
||||
// binding.historyChart.setSkipEnabled(data.isSkipEnabled)
|
||||
// if (data.isNumerical) {
|
||||
// binding.historyChart.setNumerical(true)
|
||||
// }
|
||||
binding.chart.postInvalidate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,7 @@
|
||||
<dimen name="baseSize">20dp</dimen>
|
||||
<dimen name="checkmarkWidth">48dp</dimen>
|
||||
<dimen name="checkmarkHeight">48dp</dimen>
|
||||
<dimen name="history_editor_max_height">450dp</dimen>
|
||||
<dimen name="history_editor_padding">8dp</dimen>
|
||||
<dimen name="history_editor_max_height">350dp</dimen>
|
||||
<dimen name="regularTextSize">16sp</dimen>
|
||||
<dimen name="smallTextSize">14sp</dimen>
|
||||
<dimen name="smallerTextSize">12sp</dimen>
|
||||
|
||||
Reference in New Issue
Block a user