From 354c930d85c331d394171152f52c56c8104c9058 Mon Sep 17 00:00:00 2001 From: "Alinson S. Xavier" Date: Thu, 31 Dec 2020 15:20:00 -0600 Subject: [PATCH] Replace BarChart by new Kotlin implementation --- .../activities/common/views/BarChartTest.java | 83 --- .../org/isoron/platform/gui/AndroidCanvas.kt | 15 +- .../isoron/platform/gui/AndroidDataView.kt | 109 ++++ .../isoron/platform/gui/AndroidTestView.kt | 34 ++ .../org/isoron/platform/gui/AndroidView.kt | 39 ++ .../activities/AndroidThemeSwitcher.kt | 14 +- .../activities/common/views/BarChart.java | 474 ------------------ .../habits/show/ShowHabitActivity.kt | 7 +- .../habits/show/views/BarCardView.kt | 14 +- .../src/main/res/layout/canvas_test.xml | 2 +- .../src/main/res/layout/show_habit_bar.xml | 4 +- .../assets/test/components/BarChart/base.png | Bin 10239 -> 0 bytes .../test/components/CalendarChart/base.png | Bin 37881 -> 0 bytes .../test/components/CalendarChart/scroll.png | Bin 36152 -> 0 bytes .../assets/test/components/CanvasTest.png | Bin 24849 -> 0 bytes .../components/CheckmarkButton/explicit.png | Bin 350 -> 0 bytes .../components/CheckmarkButton/implicit.png | Bin 345 -> 0 bytes .../components/CheckmarkButton/unchecked.png | Bin 424 -> 0 bytes .../test/components/HabitListHeader/light.png | Bin 4278 -> 0 bytes .../components/NumberButton/render_above.png | Bin 1653 -> 0 bytes .../components/NumberButton/render_below.png | Bin 1341 -> 0 bytes .../components/NumberButton/render_zero.png | Bin 1322 -> 0 bytes .../assets/test/components/Ring/draw1.png | Bin 3606 -> 0 bytes .../platform/gui/{Component.kt => View.kt} | 7 +- .../java/org/isoron/platform/time/Dates.kt | 10 +- .../isoron/uhabits/core/models/Timestamp.java | 9 + .../isoron/uhabits/core/ui/ThemeSwitcher.java | 3 + .../core/ui/screens/habits/show/ShowHabit.kt | 3 + .../ui/screens/habits/show/views/BarCard.kt | 4 + .../isoron/uhabits/core/ui/views/BarChart.kt | 21 +- .../uhabits/core/ui/views/CalendarChart.kt | 4 +- .../uhabits/core/ui/views/CheckmarkButton.kt | 4 +- .../uhabits/core/ui/views/HabitListHeader.kt | 4 +- .../uhabits/core/ui/views/NumberButton.kt | 4 +- .../org/isoron/uhabits/core/ui/views/Ring.kt | 4 +- .../isoron/uhabits/core/ui/views/Themes.kt | 76 ++- .../org/isoron/platform/gui/JavaCanvasTest.kt | 6 +- .../uhabits/core/ui/views/BarChartTest.kt | 19 +- 38 files changed, 339 insertions(+), 634 deletions(-) delete mode 100644 android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java create mode 100644 android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt create mode 100644 android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidTestView.kt create mode 100644 android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt delete mode 100644 android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java delete mode 100644 android/uhabits-core/assets/test/components/BarChart/base.png delete mode 100644 android/uhabits-core/assets/test/components/CalendarChart/base.png delete mode 100644 android/uhabits-core/assets/test/components/CalendarChart/scroll.png delete mode 100644 android/uhabits-core/assets/test/components/CanvasTest.png delete mode 100644 android/uhabits-core/assets/test/components/CheckmarkButton/explicit.png delete mode 100644 android/uhabits-core/assets/test/components/CheckmarkButton/implicit.png delete mode 100644 android/uhabits-core/assets/test/components/CheckmarkButton/unchecked.png delete mode 100644 android/uhabits-core/assets/test/components/HabitListHeader/light.png delete mode 100644 android/uhabits-core/assets/test/components/NumberButton/render_above.png delete mode 100644 android/uhabits-core/assets/test/components/NumberButton/render_below.png delete mode 100644 android/uhabits-core/assets/test/components/NumberButton/render_zero.png delete mode 100644 android/uhabits-core/assets/test/components/Ring/draw1.png rename android/uhabits-core/src/main/java/org/isoron/platform/gui/{Component.kt => View.kt} (89%) diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java deleted file mode 100644 index e78e4f0cb..000000000 --- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/BarChartTest.java +++ /dev/null @@ -1,83 +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.common.views; - -import androidx.test.filters.*; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.utils.*; -import org.junit.*; -import org.junit.runner.*; - -@RunWith(AndroidJUnit4.class) -@MediumTest -public class BarChartTest extends BaseViewTest -{ - private static final String BASE_PATH = "common/BarChart/"; - - private BarChart view; - - @Override - @Before - public void setUp() - { - super.setUp(); - Habit habit = fixtures.createLongNumericalHabit(); - view = new BarChart(targetContext); - Timestamp today = DateUtils.getToday(); - EntryList entries = habit.getComputedEntries(); - view.setEntries(entries.getByInterval(today.minus(20), today)); - view.setColor(PaletteUtilsKt.toThemedAndroidColor(habit.getColor(), targetContext)); - measureView(view, dpToPixels(300), dpToPixels(200)); - } - - @Test - public void testRender() throws Throwable - { - assertRenders(view, BASE_PATH + "render.png"); - } - - @Test - public void testRender_withDataOffset() throws Throwable - { - view.onScroll(null, null, -dpToPixels(150), 0); - view.invalidate(); - - assertRenders(view, BASE_PATH + "renderDataOffset.png"); - } - - @Test - public void testRender_withDifferentSize() throws Throwable - { - measureView(view, dpToPixels(200), dpToPixels(200)); - assertRenders(view, BASE_PATH + "renderDifferentSize.png"); - } - - @Test - public void testRender_withTransparentBackground() throws Throwable - { - view.setIsTransparencyEnabled(true); - assertRenders(view, BASE_PATH + "renderTransparent.png"); - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt index 6cd92fb9a..9d9c38743 100644 --- a/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt +++ b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt @@ -25,8 +25,6 @@ import android.graphics.Paint import android.graphics.Rect import android.graphics.Typeface import android.text.TextPaint -import android.util.AttributeSet -import android.view.View import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome class AndroidCanvas : Canvas { @@ -107,7 +105,7 @@ class AndroidCanvas : Canvas { } override fun setFontSize(size: Double) { - textPaint.textSize = size.toDp() * 1.07f + textPaint.textSize = size.toDp() } override fun setStrokeWidth(size: Double) { @@ -156,14 +154,3 @@ class AndroidCanvas : Canvas { return AndroidImage(bmp) } } - -class AndroidCanvasTestView(context: Context, attrs: AttributeSet) : View(context, attrs) { - val canvas = AndroidCanvas() - - override fun onDraw(canvas: android.graphics.Canvas) { - this.canvas.context = context - this.canvas.innerCanvas = canvas - this.canvas.density = resources.displayMetrics.density.toDouble() - this.canvas.drawTestImage() - } -} diff --git a/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt new file mode 100644 index 000000000..ec4ba4dc7 --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt @@ -0,0 +1,109 @@ +/* + * 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.platform.gui + +import android.animation.ValueAnimator +import android.content.Context +import android.util.AttributeSet +import android.view.GestureDetector +import android.view.MotionEvent +import android.widget.Scroller + +/** + * An AndroidView that implements scrolling. + */ +class AndroidDataView( + context: Context, + attrs: AttributeSet, +) : AndroidView(context, attrs), + GestureDetector.OnGestureListener, + ValueAnimator.AnimatorUpdateListener { + + private val detector = GestureDetector(context, this) + private val scroller = Scroller(context, null, true) + private val scrollAnimator = ValueAnimator.ofFloat(0f, 1f).apply { + addUpdateListener(this@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 onLongPress(e: MotionEvent?) = Unit + + override fun onScroll( + e1: MotionEvent?, + e2: MotionEvent?, + dx: Float, + dy: Float, + ): Boolean { + if (Math.abs(dx) > Math.abs(dy)) { + val parent = parent + parent?.requestDisallowInterceptTouchEvent(true) + } + scroller.startScroll( + scroller.currX, + scroller.currY, + -dx.toInt(), + dy.toInt(), + 0 + ) + scroller.computeScrollOffset() + updateDataOffset() + return true + } + + override fun onFling( + e1: MotionEvent?, + e2: MotionEvent?, + velocityX: Float, + velocityY: Float, + ): Boolean { + scroller.fling(scroller.currX, scroller.currY, velocityX.toInt() / 2, 0, 0, 10000, 0, 0) + invalidate() + scrollAnimator.duration = scroller.duration.toLong() + scrollAnimator.start() + return false + } + + override fun onAnimationUpdate(animation: ValueAnimator?) { + if (!scroller.isFinished) { + scroller.computeScrollOffset() + updateDataOffset() + } else { + scrollAnimator.cancel() + } + } + + fun resetDataOffset() { + scroller.finalX = 0 + scroller.computeScrollOffset() + updateDataOffset() + } + + private fun updateDataOffset() { + var newDataOffset: Int = scroller.currX / (view.dataColumnWidth * canvas.density).toInt() + newDataOffset = Math.max(0, newDataOffset) + if (newDataOffset != view.dataOffset) { + view.dataOffset = newDataOffset + postInvalidate() + } + } +} diff --git a/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidTestView.kt b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidTestView.kt new file mode 100644 index 000000000..9f7a532de --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidTestView.kt @@ -0,0 +1,34 @@ +/* + * 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.platform.gui + +import android.content.Context +import android.util.AttributeSet + +class AndroidTestView(context: Context, attrs: AttributeSet) : android.view.View(context, attrs) { + val canvas = AndroidCanvas() + + override fun onDraw(canvas: android.graphics.Canvas) { + this.canvas.context = context + this.canvas.innerCanvas = canvas + this.canvas.density = resources.displayMetrics.density.toDouble() + this.canvas.drawTestImage() + } +} diff --git a/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt new file mode 100644 index 000000000..9709e2fc1 --- /dev/null +++ b/android/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt @@ -0,0 +1,39 @@ +/* + * 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.platform.gui + +import android.content.Context +import android.util.AttributeSet + +open class AndroidView( + context: Context, + attrs: AttributeSet, +) : android.view.View(context, attrs) { + + lateinit var view: T + val canvas = AndroidCanvas() + + override fun onDraw(canvas: android.graphics.Canvas) { + this.canvas.context = context + this.canvas.innerCanvas = canvas + this.canvas.density = resources.displayMetrics.density.toDouble() + view.draw(this.canvas) + } +} diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt index 6b7779534..3ce23e4fa 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt @@ -28,6 +28,9 @@ import androidx.core.content.ContextCompat import org.isoron.uhabits.R import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.ui.ThemeSwitcher +import org.isoron.uhabits.core.ui.views.DarkTheme +import org.isoron.uhabits.core.ui.views.LightTheme +import org.isoron.uhabits.core.ui.views.Theme import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.inject.ActivityScope @@ -35,9 +38,11 @@ import org.isoron.uhabits.inject.ActivityScope class AndroidThemeSwitcher constructor( @ActivityContext val context: Context, - preferences: Preferences + preferences: Preferences, ) : ThemeSwitcher(preferences) { + private var currentTheme: Theme = LightTheme() + override fun getSystemTheme(): Int { if (SDK_INT < 29) return THEME_LIGHT val uiMode = context.resources.configuration.uiMode @@ -48,17 +53,24 @@ constructor( } } + override fun getCurrentTheme(): Theme { + return currentTheme + } + override fun applyDarkTheme() { + currentTheme = DarkTheme() context.setTheme(R.style.AppBaseThemeDark) (context as Activity).window.navigationBarColor = ContextCompat.getColor(context, R.color.grey_900) } override fun applyLightTheme() { + currentTheme = LightTheme() context.setTheme(R.style.AppBaseTheme) } override fun applyPureBlackTheme() { + currentTheme = DarkTheme() context.setTheme(R.style.AppBaseThemeDark_PureBlack) (context as Activity).window.navigationBarColor = ContextCompat.getColor(context, R.color.black) diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java deleted file mode 100644 index eca566793..000000000 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/BarChart.java +++ /dev/null @@ -1,474 +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.common.views; - -import android.content.*; -import android.graphics.*; -import android.util.*; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import org.isoron.uhabits.*; -import org.isoron.uhabits.activities.habits.list.views.*; -import org.isoron.uhabits.core.models.*; -import org.isoron.uhabits.core.utils.*; -import org.isoron.uhabits.utils.*; - -import java.text.*; -import java.util.*; - -import static org.isoron.uhabits.utils.InterfaceUtils.*; - -public class BarChart extends ScrollableChart -{ - private static final PorterDuffXfermode XFERMODE_CLEAR = - new PorterDuffXfermode(PorterDuff.Mode.CLEAR); - - private static final PorterDuffXfermode XFERMODE_SRC = - new PorterDuffXfermode(PorterDuff.Mode.SRC); - - private Paint pGrid; - - private float em; - - private SimpleDateFormat dfMonth; - - private SimpleDateFormat dfDay; - - private SimpleDateFormat dfYear; - - private Paint pText, pGraph; - - private RectF rect, prevRect; - - private int baseSize; - - private int paddingTop; - - private float columnWidth; - - private int columnHeight; - - private int nColumns; - - private int textColor; - - private int gridColor; - - @Nullable - private List entries; - - private int bucketSize = 7; - - private int backgroundColor; - - private Bitmap drawingCache; - - private Canvas cacheCanvas; - - private boolean isTransparencyEnabled; - - private int skipYear = 0; - - private String previousYearText; - - private String previousMonthText; - - private double maxValue; - - private int primaryColor; - - public BarChart(Context context) - { - super(context); - init(); - } - - public BarChart(Context context, AttributeSet attrs) - { - super(context, attrs); - init(); - } - - public void populateWithRandomData() - { - Random random = new Random(); - List entries = new LinkedList<>(); - - Timestamp today = DateUtils.getToday(); - - for (int i = 1; i < 100; i++) - { - int value = random.nextInt(1000); - entries.add(new Entry(today.minus(i), value)); - } - - setEntries(entries); - } - - public void setBucketSize(int bucketSize) - { - this.bucketSize = bucketSize; - postInvalidate(); - } - - public void setEntries(@NonNull List entries) - { - this.entries = entries; - - maxValue = 1.0; - for (Entry e : entries) - maxValue = Math.max(maxValue, e.getValue()); - maxValue = Math.ceil(maxValue / 1000 * 1.05) * 1000; - - postInvalidate(); - } - - public void setColor(int primaryColor) - { - StyledResources res = new StyledResources(getContext()); - this.primaryColor = primaryColor; - postInvalidate(); - } - - public void setIsTransparencyEnabled(boolean enabled) - { - this.isTransparencyEnabled = enabled; - postInvalidate(); - } - - @Override - protected void onDraw(Canvas canvas) - { - super.onDraw(canvas); - Canvas activeCanvas; - - if (isTransparencyEnabled) - { - if (drawingCache == null) initCache(getWidth(), getHeight()); - - activeCanvas = cacheCanvas; - drawingCache.eraseColor(Color.TRANSPARENT); - } - else - { - activeCanvas = canvas; - } - - if (entries == null) return; - - rect.set(0, 0, nColumns * columnWidth, columnHeight); - rect.offset(0, paddingTop); - - drawGrid(activeCanvas, rect); - - pText.setColor(textColor); - pGraph.setColor(primaryColor); - prevRect.setEmpty(); - - previousMonthText = ""; - previousYearText = ""; - skipYear = 0; - - for (int k = 0; k < nColumns; k++) - { - int offset = nColumns - k - 1 + getDataOffset(); - if (offset >= entries.size()) continue; - - double value = entries.get(offset).getValue(); - Timestamp timestamp = entries.get(offset).getTimestamp(); - int height = (int) (columnHeight * value / maxValue); - - rect.set(0, 0, baseSize, height); - rect.offset(k * columnWidth + (columnWidth - baseSize) / 2, - paddingTop + columnHeight - height); - - drawValue(activeCanvas, rect, value); - drawBar(activeCanvas, rect, value); - - prevRect.set(rect); - rect.set(0, 0, columnWidth, columnHeight); - rect.offset(k * columnWidth, paddingTop); - - drawFooter(activeCanvas, rect, timestamp); - } - - if (activeCanvas != canvas) canvas.drawBitmap(drawingCache, 0, 0, null); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) - { - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - setMeasuredDimension(width, height); - } - - @Override - protected void onSizeChanged(int width, - int height, - int oldWidth, - int oldHeight) - { - if (height < 9) height = 200; - - float maxTextSize = getDimension(getContext(), R.dimen.tinyTextSize); - float textSize = height * 0.06f; - pText.setTextSize(Math.min(textSize, maxTextSize)); - em = pText.getFontSpacing(); - - int footerHeight = (int) (3 * em); - paddingTop = (int) (em); - - baseSize = (height - footerHeight - paddingTop) / 12; - columnWidth = baseSize; - columnWidth = Math.max(columnWidth, getMaxDayWidth() * 1.5f); - columnWidth = Math.max(columnWidth, getMaxMonthWidth() * 1.2f); - - nColumns = (int) (width / columnWidth); - columnWidth = (float) width / nColumns; - setScrollerBucketSize((int) columnWidth); - - columnHeight = 12 * baseSize; - - float minStrokeWidth = dpToPixels(getContext(), 1); - pGraph.setTextSize(baseSize * 0.5f); - pGraph.setStrokeWidth(baseSize * 0.1f); - pGrid.setStrokeWidth(Math.min(minStrokeWidth, baseSize * 0.05f)); - - if (isTransparencyEnabled) initCache(width, height); - } - - private void drawBar(Canvas canvas, RectF rect, double value) - { - float margin = baseSize * 0.225f; - float round = dpToPixels(getContext(), 2); - - int color = primaryColor; - - rect.inset(-margin, 0); - setModeOrColor(pGraph, XFERMODE_CLEAR, backgroundColor); - canvas.drawRoundRect(rect, round, round, pGraph); - - rect.inset(margin, 0); - setModeOrColor(pGraph, XFERMODE_SRC, color); - canvas.drawRoundRect(rect, round, round, pGraph); - rect.set(rect.left, - rect.top + rect.height() / 2.0f, - rect.right, - rect.bottom); - canvas.drawRect(rect, pGraph); - - if (isTransparencyEnabled) pGraph.setXfermode(XFERMODE_SRC); - } - - private void drawFooter(Canvas canvas, RectF rect, Timestamp currentDate) - { - String yearText = dfYear.format(currentDate.toJavaDate()); - String monthText = dfMonth.format(currentDate.toJavaDate()); - String dayText = dfDay.format(currentDate.toJavaDate()); - - GregorianCalendar calendar = currentDate.toCalendar(); - pText.setColor(textColor); - - String text; - int year = calendar.get(Calendar.YEAR); - - boolean shouldPrintYear = true; - if (yearText.equals(previousYearText)) shouldPrintYear = false; - - if (skipYear > 0) - { - skipYear--; - shouldPrintYear = false; - } - - if (bucketSize >= 365) shouldPrintYear = true; - - if (shouldPrintYear) - { - previousYearText = yearText; - previousMonthText = ""; - - pText.setTextAlign(Paint.Align.CENTER); - canvas.drawText(yearText, rect.centerX(), rect.bottom + em * 2.2f, pText); - skipYear = 1; - - - } - - if (bucketSize < 365) - { - if (!monthText.equals(previousMonthText)) - { - previousMonthText = monthText; - text = monthText; - } - else - { - text = dayText; - } - - canvas.drawText(text, rect.centerX(), rect.bottom + em * 1.2f, - pText); - } - } - - private void drawGrid(Canvas canvas, RectF rGrid) - { - int nRows = 5; - float rowHeight = rGrid.height() / nRows; - - pText.setColor(textColor); - pGrid.setColor(gridColor); - - for (int i = 0; i < nRows; i++) - { - canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, - pGrid); - rGrid.offset(0, rowHeight); - } - - canvas.drawLine(rGrid.left, rGrid.top, rGrid.right, rGrid.top, pGrid); - } - - private void drawValue(Canvas canvas, RectF rect, double value) - { - if (value == 0) return; - int activeColor = primaryColor; - - String label = NumberButtonViewKt.toShortString(value / 1000); - Rect rText = new Rect(); - pText.getTextBounds(label, 0, label.length(), rText); - - float offset = 0.5f * em; - float x = rect.centerX(); - float y = rect.top - offset; - int cap = (int) (-0.1f * em); - - rText.offset((int) x, (int) y); - rText.offset(-rText.width() / 2, 0); - rText.inset(3 * cap, cap); - - setModeOrColor(pText, XFERMODE_CLEAR, backgroundColor); - canvas.drawRect(rText, pText); - - setModeOrColor(pText, XFERMODE_SRC, activeColor); - canvas.drawText(label, x, y, pText); - } - - private float getMaxDayWidth() - { - float maxDayWidth = 0; - GregorianCalendar day = DateUtils.getStartOfTodayCalendarWithOffset(); - - for (int i = 0; i < 28; i++) - { - day.set(Calendar.DAY_OF_MONTH, i); - float monthWidth = pText.measureText(dfMonth.format(day.getTime())); - maxDayWidth = Math.max(maxDayWidth, monthWidth); - } - - return maxDayWidth; - } - - private float getMaxMonthWidth() - { - float maxMonthWidth = 0; - GregorianCalendar day = DateUtils.getStartOfTodayCalendarWithOffset(); - - for (int i = 0; i < 12; i++) - { - day.set(Calendar.MONTH, i); - float monthWidth = pText.measureText(dfMonth.format(day.getTime())); - maxMonthWidth = Math.max(maxMonthWidth, monthWidth); - } - - return maxMonthWidth; - } - - private void init() - { - initPaints(); - initColors(); - initDateFormats(); - initRects(); - } - - private void initCache(int width, int height) - { - if (drawingCache != null) drawingCache.recycle(); - drawingCache = - Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - cacheCanvas = new Canvas(drawingCache); - } - - private void initColors() - { - StyledResources res = new StyledResources(getContext()); - - primaryColor = Color.BLACK; - textColor = res.getColor(R.attr.mediumContrastTextColor); - gridColor = res.getColor(R.attr.lowContrastTextColor); - backgroundColor = res.getColor(R.attr.cardBgColor); - } - - private void initDateFormats() - { - if (isInEditMode()) - { - dfYear = new SimpleDateFormat("yyyy", Locale.US); - dfMonth = new SimpleDateFormat("MMM", Locale.US); - dfDay = new SimpleDateFormat("d", Locale.US); - return; - } - - dfYear = DateExtensionsKt.toSimpleDataFormat("yyyy"); - dfMonth = DateExtensionsKt.toSimpleDataFormat("MMM"); - dfDay = DateExtensionsKt.toSimpleDataFormat("d"); - } - - private void initPaints() - { - pText = new Paint(); - pText.setAntiAlias(true); - pText.setTextAlign(Paint.Align.CENTER); - - pGraph = new Paint(); - pGraph.setTextAlign(Paint.Align.CENTER); - pGraph.setAntiAlias(true); - - pGrid = new Paint(); - pGrid.setAntiAlias(true); - } - - private void initRects() - { - rect = new RectF(); - prevRect = new RectF(); - } - - private void setModeOrColor(Paint p, PorterDuffXfermode mode, int color) - { - if (isTransparencyEnabled) p.setXfermode(mode); - else p.setColor(color); - } -} 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 9b22bdfef..75f3145d7 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 @@ -43,13 +43,14 @@ import org.isoron.uhabits.intents.IntentFactory class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { - private val presenter = ShowHabitPresenter() + val presenter = ShowHabitPresenter() private lateinit var commandRunner: CommandRunner private lateinit var menu: ShowHabitMenu private lateinit var view: ShowHabitView private lateinit var habit: Habit private lateinit var preferences: Preferences + private lateinit var themeSwitcher: AndroidThemeSwitcher private val scope = CoroutineScope(Dispatchers.Main) @@ -61,7 +62,8 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { habit = habitList.getById(ContentUris.parseId(intent.data!!))!! preferences = appComponent.preferences commandRunner = appComponent.commandRunner - AndroidThemeSwitcher(this, preferences).apply() + themeSwitcher = AndroidThemeSwitcher(this, preferences) + themeSwitcher.apply() view = ShowHabitView(this) @@ -134,6 +136,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { presenter.present( habit = habit, preferences = preferences, + theme = themeSwitcher.currentTheme, ) ) } diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt index 44c7a40f2..dfac3233b 100644 --- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt +++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt @@ -24,9 +24,12 @@ import android.view.LayoutInflater import android.view.View import android.widget.AdapterView import android.widget.LinearLayout +import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.uhabits.core.ui.screens.habits.show.views.BarCardViewModel +import org.isoron.uhabits.core.ui.views.BarChart import org.isoron.uhabits.databinding.ShowHabitBarBinding import org.isoron.uhabits.utils.toThemedAndroidColor +import java.util.Locale class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { @@ -35,11 +38,16 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, var onBoolSpinnerPosition: (position: Int) -> Unit = {} fun update(data: BarCardViewModel) { - binding.barChart.setEntries(data.entries) - binding.barChart.setBucketSize(data.bucketSize) val androidColor = data.color.toThemedAndroidColor(context) + binding.chart.view = BarChart(data.theme, JavaLocalDateFormatter(Locale.US)).apply { + series = mutableListOf(data.entries.map { it.value / 1000.0 }) + colors = mutableListOf(theme.color(data.color.paletteIndex)) + axis = data.entries.map { it.timestamp.toLocalDate() } + } + binding.chart.resetDataOffset() + binding.chart.postInvalidate() + binding.title.setTextColor(androidColor) - binding.barChart.setColor(androidColor) if (data.isNumerical) { binding.boolSpinner.visibility = GONE } else { diff --git a/android/uhabits-android/src/main/res/layout/canvas_test.xml b/android/uhabits-android/src/main/res/layout/canvas_test.xml index 2d2cee167..6faa0df2e 100644 --- a/android/uhabits-android/src/main/res/layout/canvas_test.xml +++ b/android/uhabits-android/src/main/res/layout/canvas_test.xml @@ -22,7 +22,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> - \ No newline at end of file diff --git a/android/uhabits-android/src/main/res/layout/show_habit_bar.xml b/android/uhabits-android/src/main/res/layout/show_habit_bar.xml index 5377a35ba..f696e30e3 100644 --- a/android/uhabits-android/src/main/res/layout/show_habit_bar.xml +++ b/android/uhabits-android/src/main/res/layout/show_habit_bar.xml @@ -52,8 +52,8 @@ android:layout_alignParentTop="true" android:text="@string/history" /> - diff --git a/android/uhabits-core/assets/test/components/BarChart/base.png b/android/uhabits-core/assets/test/components/BarChart/base.png deleted file mode 100644 index 4bb551c99d6af6e2a4de71994b3160732d731014..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10239 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 Pfq$wuZe1@?unPWvs8bJ* diff --git a/android/uhabits-core/assets/test/components/CalendarChart/scroll.png b/android/uhabits-core/assets/test/components/CalendarChart/scroll.png deleted file mode 100644 index 16744a297e555a4b31aac013d8603bc5da674816..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36152 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 aj*zJZPp>I;adSf8pPG{9jiPIo0sjwh9Y!Gl diff --git a/android/uhabits-core/assets/test/components/CanvasTest.png b/android/uhabits-core/assets/test/components/CanvasTest.png deleted file mode 100644 index 75b3d8f2095e497c76b49afa0430113e497ff909..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24849 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 N44$rjF6*2UngH#{jKcr` diff --git a/android/uhabits-core/assets/test/components/CheckmarkButton/explicit.png b/android/uhabits-core/assets/test/components/CheckmarkButton/explicit.png deleted file mode 100644 index c2b66f74ecef65a31519752ebf2ab34b1c37609e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U{v*VaSW-r_4bCL*Wmz};~&jC zwikTm>eI7r=x*+q+&oe+Q9Jnx@gM&x zJUzUC1|qZq4}}^8NeK_f~aNE2lBwl&9s4U&QAB9AN3}O-gbTTKhh0Ub3pJ2zYLHP-~6L-{)&BNyZ+|}&RH6`&pWhI e0Te)R;84XnYeI4HU*$KQATdu@KbLh*2~7aK@Ri*F diff --git a/android/uhabits-core/assets/test/components/CheckmarkButton/implicit.png b/android/uhabits-core/assets/test/components/CheckmarkButton/implicit.png deleted file mode 100644 index acc067024e8b6b82671a930b56788ecf266a3f70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>U{vsQaSW-r_4bCL*I@>c;}3Zr z>F%mxbrb*lled{{*7q;9#(!V>P`tN;~?aYsAr5*p=+oqj0h&mTd#e?sV9fV)aSW-r_4d|!ujW9R;|~?t zCMOu&J|b<6ISe*gVfImcF2ynDawM>*v>OUvym z%OBr+xxD)P;fEg_E>?Y9zI?LeeGc!Qc*{dQKip0TPRx7eGRM-%_0LO5?HJnwu}&xS zl~s=Yx5!V8T({EZ|JNdkg>gadCpzMf?GWc${#R5cwP!*}(hBcXX(`7)Z0-X44+TliyPe;w_TKZmW8G=EErbOTAPf!nKk-?7JLs>MTXPd6?CI*~vd$@? F2>=h$z83%h diff --git a/android/uhabits-core/assets/test/components/HabitListHeader/light.png b/android/uhabits-core/assets/test/components/HabitListHeader/light.png deleted file mode 100644 index c146b916d3c5581b0b880643845b388caa4628f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4278 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 E095lBwEzGB diff --git a/android/uhabits-core/assets/test/components/NumberButton/render_above.png b/android/uhabits-core/assets/test/components/NumberButton/render_above.png deleted file mode 100644 index 4673ef0f355df5f3966d86caa94dc0a83cc6f0e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1653 zcmV-*28#KKP);Xn* zd+s_8000000000000000000000000Q#@xBboSy$qsb}7OxtQ#kLr%v#E1pZ@b61?M zx8(G^51fnb1LgW?Nlq>4`A5VH?UZ^t{^cB_J}cT?&ydk~x~^AXaM+PkYr6ilRRhrM z=z9Mbly!CFa_T<=ykpi3&~EP&f4@^s9y5Y%$!W+8IBCrQqy)CTcTIfHg82Ow^Y?*s z!Fy^XavDL$y^wkt3bgI^WX3aLFu*-VX=k(<_cPOGb|i9|VE~a?=r2-bB=uTvFmB-< zo6)34?_KM1n&W~*0MlQ@G{UnDd4?I0mki(eU#jhb_l#9J4GO|PXfLrG}D1{q+hWEx5{WQviqksi6NHw&k}-g5HoUwuwz|8_$3=L<}Z;Udg4C&*n zaYosaGj>q$<+d!cbMp6i#rc;R#eHH`&KMeCJ=*~8mxXh3F4qs0Y)j5qp|YhxW^km% zT9JKvldLeSvL&Yxm=;yVwygV!Hgr6wGO1*srX$Z}*2O9Kj&(T=aVuge@Bbr%8Lc+s zS&bTHd!Vhkyqm@y&QZx}M5;-?SDpp<({c}9 z1?IhvB$xd1Q0A17w|`gV000000000007X{G6S63a3TMGCK*xMzd)!x#5k46mc5p-` z>?I69v!+Uw_3*Qk*7{#d7FsU`6$k_EK<1X*Atfcu&AcjIPjWkYJ$llL*e{IK(GKv% z?|#p?d8TTPZU!^$q*e^J>2%zSspH6^{jV+R0$e}Z(v>CQvKsF9;3d|Akx#YyD^bC$ zs@YkIo;akWuJ=cDp+d@&GQ(oqHP#49fm^X_Nozq>-b(D`>vqBjMf+c4pS~O@s+Ia1 z?fL8XfR!?`T~JupA3wW|W<_w-luo&L1E|rfm!Z#{doH@JL^Gjk|LbRfK%u6(dsBOp z0i>dWN(pY1le-v}GfuDu=(%4R3_BHF90@;Lw*NJp0lnx>)qLyqM>YVR5$E04jTEhw znnyFhpU(JfKT!CQO8u`L%3t4z1+QOa05qL`Gm26wWl{{I=0P!?4Il2$0vY@j4ujNSRUPje|20qn&E2gBY zxh`f{Dt=w$;s+Vod*sU6ybc)1ekF7IgE1e!Sh@c-T?cGR#mZYI@~Y2bY#ZQ)7G#em zO2x_L&~?yw)DaK^bjHwo}EneVGlJ4X`SMIJKcQ0e!CP{TnFrexfL>Z2#+- z{jm4GHspUJVYdvVpWjOCyXfsGJtSAc-KJ3^^Mug=vMgQZ_sN=nGG6MxsZ{8HO?N@} z$*D>K%XAe~-=(B{ofbcN{+Oz#Nv>);nHvMby&mPN4#|Gy?QoXuKgciu7dHS500RIR zV7yT&>I%xu0RR91000000000000000*i9Y+o&kXm^TF1E00000NkvXXu0mjfG-f0B diff --git a/android/uhabits-core/assets/test/components/NumberButton/render_below.png b/android/uhabits-core/assets/test/components/NumberButton/render_below.png deleted file mode 100644 index c3ffb68de1ea49a52cd17a8bbd7da136e6c1d2a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1341 zcmV-D1;YA?P)x8bKd8D-rsZnJm=qAR0IG300000 z00000000000000000000fFJ1Y?ym0Y>bld}**Qd#;_Hr%j*ErXb?iap+#qsRiKsn? zER)pdTbCCgvYrQ!^^Xv_kMpI=7xEuuN|;96{it<$0V1G`Nc&|W<~zw4$tcN&na=n0 z_xG1arOPJ=v{?vQB|=WAJOcv*C+WW>3$a~M>GG-hd2MMD?phpGX(4SrDqTL+fOV4$ zy~G-MKUhlm`6zVx%L8I3zj=akj zf_tLS<&y&@EJVDqjBMK-ar{sey1bfxaFFqin*lJ zFp+E+zm#OoAdEZE zvO?5+ePFg%OA1mk;CrfgHvnb;p& z^7#lT8Mq}zFYvs(tV}J*ODs#ihjcwHQ^aazYFde|lS!igK1#kXvIlfRyLZ{<1SXJI z!icm-TD~;vS1V-n`$=~~ruN6V^iRk-YrC1oQ^MvMT_HTM2@(?aWO*@Z)QUMtduDTh zR(czavDZ&A4dl$LL0Np-|VPS6_UPXE9L6Ak&vBmIAF-}?0RieRw9i3acqJH zq{e$tC{nENj?aDX~=u`8XbQ_PaC91yhgK|P

y7`pFe8aalTGOzs;FQ3zBGs10zyj9vq>wf}!|#AR*Y{`E{9ph8HFfWkW9 zkO*s2^f!dD|9=~xjayE&C_)8@Gg4#5|ypg{} z>*&(bkLVBk-l;mhApa#rHCq5}3ZesmkC2d3BGnB3Uv5bCP zUnJpEDz?EClWuID-8J(`c$l&s#^#b~J7ldnfWM+LXdcRA=k@mXo;|Alajgj@TvfTl zA~~1IEG5V5Joq`RJ?3vZuwKcVJgg5;b3M{jT@t&JxwIb$aDcbp0)hkJ05|{+@Y?}X z5>}Ri4FCWD00000000000000000000C=`AJrh#MP=hI$+00000NkvXXu0mjfFNbqq diff --git a/android/uhabits-core/assets/test/components/NumberButton/render_zero.png b/android/uhabits-core/assets/test/components/NumberButton/render_zero.png deleted file mode 100644 index 235de2f627ba81e14eeef070e39f4a6d0109bcf1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1322 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 return unixTime; } + public LocalDate toLocalDate() + { + long millisSince2000 = unixTime - 946684800000L; + int daysSince2000 = (int) (millisSince2000 / 86400000); + return new LocalDate(daysSince2000); + } + /** * Returns -1 if this timestamp is older than the given timestamp, 1 if this * timestamp is newer, or zero if they are equal. diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/ThemeSwitcher.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/ThemeSwitcher.java index e0e35a739..7c83130fa 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/ThemeSwitcher.java +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/ThemeSwitcher.java @@ -22,6 +22,7 @@ package org.isoron.uhabits.core.ui; import androidx.annotation.*; import org.isoron.uhabits.core.preferences.*; +import org.isoron.uhabits.core.ui.views.*; public abstract class ThemeSwitcher { @@ -59,6 +60,8 @@ public abstract class ThemeSwitcher public abstract int getSystemTheme(); + public abstract Theme getCurrentTheme(); + public boolean isNightMode() { int systemTheme = getSystemTheme(); diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt index 72cce2936..bbd8731be 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/ShowHabit.kt @@ -40,6 +40,7 @@ import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardPresente import org.isoron.uhabits.core.ui.screens.habits.show.views.SubtitleCardViewModel import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.views.TargetCardViewModel +import org.isoron.uhabits.core.ui.views.Theme data class ShowHabitViewModel( val title: String = "", @@ -60,6 +61,7 @@ class ShowHabitPresenter { fun present( habit: Habit, preferences: Preferences, + theme: Theme, ): ShowHabitViewModel { return ShowHabitViewModel( title = habit.name, @@ -100,6 +102,7 @@ class ShowHabitPresenter { firstWeekday = preferences.firstWeekday, boolSpinnerPosition = preferences.barCardBoolSpinnerPosition, numericalSpinnerPosition = preferences.barCardNumericalSpinnerPosition, + theme = theme, ), ) } diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt index e91ded06f..1abad408d 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/show/views/BarCard.kt @@ -23,9 +23,11 @@ import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.PaletteColor import org.isoron.uhabits.core.models.groupedSum +import org.isoron.uhabits.core.ui.views.Theme import org.isoron.uhabits.core.utils.DateUtils data class BarCardViewModel( + val theme: Theme, val boolSpinnerPosition: Int, val bucketSize: Int, val color: PaletteColor, @@ -43,6 +45,7 @@ class BarCardPresenter { firstWeekday: Int, numericalSpinnerPosition: Int, boolSpinnerPosition: Int, + theme: Theme, ): BarCardViewModel { val bucketSize = if (habit.isNumerical) { numericalBucketSizes[numericalSpinnerPosition] @@ -57,6 +60,7 @@ class BarCardPresenter { isNumerical = habit.isNumerical, ) return BarCardViewModel( + theme = theme, entries = entries, bucketSize = bucketSize, color = habit.color, diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/BarChart.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/BarChart.kt index 638a92a0e..533b3a69e 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/BarChart.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/BarChart.kt @@ -21,7 +21,7 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color -import org.isoron.platform.gui.Component +import org.isoron.platform.gui.DataView import org.isoron.platform.gui.TextAlign import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDateFormatter @@ -32,12 +32,13 @@ import kotlin.math.round class BarChart( var theme: Theme, var dateFormatter: LocalDateFormatter, -) : Component { +) : DataView { // Data var series = mutableListOf>() var colors = mutableListOf() var axis = listOf() + override var dataOffset = 0 // Style var paddingTop = 20.0 @@ -50,6 +51,9 @@ class BarChart( var nGridlines = 6 var backgroundColor = theme.cardBackgroundColor + override val dataColumnWidth: Double + get() = barWidth + barMargin * 2 + override fun draw(canvas: Canvas) { val width = canvas.getWidth() val height = canvas.getHeight() @@ -75,8 +79,11 @@ class BarChart( barMargin fun drawColumn(s: Int, c: Int) { - val dataColumn = nColumns - c - 1 - val value = if (dataColumn < series[s].size) series[s][dataColumn] else 0.0 + val dataColumn = nColumns - c - 1 + dataOffset + val value = when { + dataColumn < 0 || dataColumn >= series[s].size -> 0.0 + else -> series[s][dataColumn] + } if (value <= 0) return val perc = value / maxValue val barHeight = round(maxBarHeight * perc) @@ -142,12 +149,12 @@ class BarChart( canvas.setTextAlign(TextAlign.CENTER) var prevMonth = -1 var prevYear = -1 - val isLargeInterval = (axis[0].distanceTo(axis[1]) > 300) + val isLargeInterval = axis.size < 2 || (axis[0].distanceTo(axis[1]) > 300) for (c in 0 until nColumns) { val x = barGroupOffset(c) - val dataColumn = nColumns - c - 1 - if (dataColumn >= axis.size) continue + val dataColumn = nColumns - c - 1 + dataOffset + if (dataColumn < 0 || dataColumn >= axis.size) continue val date = axis[dataColumn] if (isLargeInterval) { canvas.drawText( diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CalendarChart.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CalendarChart.kt index 2555e0d9e..a5f7d6bd1 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CalendarChart.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CalendarChart.kt @@ -21,8 +21,8 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color -import org.isoron.platform.gui.Component import org.isoron.platform.gui.TextAlign +import org.isoron.platform.gui.View import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDateFormatter import kotlin.math.floor @@ -33,7 +33,7 @@ class CalendarChart( var color: Color, var theme: Theme, var dateFormatter: LocalDateFormatter -) : Component { +) : View { var padding = 5.0 var backgroundColor = Color(0xFFFFFF) diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CheckmarkButton.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CheckmarkButton.kt index 3de5d4bb1..a5b28407e 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CheckmarkButton.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/CheckmarkButton.kt @@ -21,15 +21,15 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color -import org.isoron.platform.gui.Component import org.isoron.platform.gui.Font import org.isoron.platform.gui.FontAwesome +import org.isoron.platform.gui.View class CheckmarkButton( private val value: Int, private val color: Color, private val theme: Theme -) : Component { +) : View { override fun draw(canvas: Canvas) { canvas.setFont(Font.FONT_AWESOME) canvas.setFontSize(theme.smallTextSize * 1.5) diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/HabitListHeader.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/HabitListHeader.kt index 703c86a6d..8ba3d1435 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/HabitListHeader.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/HabitListHeader.kt @@ -20,8 +20,8 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas -import org.isoron.platform.gui.Component import org.isoron.platform.gui.Font +import org.isoron.platform.gui.View import org.isoron.platform.time.LocalDate import org.isoron.platform.time.LocalDateFormatter @@ -30,7 +30,7 @@ class HabitListHeader( private val nButtons: Int, private val theme: Theme, private val fmt: LocalDateFormatter -) : Component { +) : View { override fun draw(canvas: Canvas) { val width = canvas.getWidth() diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/NumberButton.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/NumberButton.kt index d991a79bd..2d645bca6 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/NumberButton.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/NumberButton.kt @@ -21,8 +21,8 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color -import org.isoron.platform.gui.Component import org.isoron.platform.gui.Font +import org.isoron.platform.gui.View import java.lang.String.format import kotlin.math.round @@ -52,7 +52,7 @@ class NumberButton( val threshold: Double, val units: String, val theme: Theme -) : Component { +) : View { override fun draw(canvas: Canvas) { val width = canvas.getWidth() diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Ring.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Ring.kt index 285f09139..3b8d022ee 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Ring.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Ring.kt @@ -21,7 +21,7 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Canvas import org.isoron.platform.gui.Color -import org.isoron.platform.gui.Component +import org.isoron.platform.gui.View import java.lang.String.format import kotlin.math.max import kotlin.math.min @@ -33,7 +33,7 @@ class Ring( val radius: Double, val theme: Theme, val label: Boolean = false -) : Component { +) : View { override fun draw(canvas: Canvas) { val width = canvas.getWidth() diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Themes.kt b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Themes.kt index 449beeba0..525977858 100644 --- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Themes.kt +++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/views/Themes.kt @@ -22,27 +22,23 @@ package org.isoron.uhabits.core.ui.views import org.isoron.platform.gui.Color abstract class Theme { - val toolbarColor = Color(0xffffff) + open val appBackgroundColor = Color(0xf4f4f4) + open val cardBackgroundColor = Color(0xFAFAFA) + open val headerBackgroundColor = Color(0xeeeeee) + open val headerBorderColor = Color(0xcccccc) + open val headerTextColor = Color(0x9E9E9E) + open val highContrastTextColor = Color(0x202020) + open val itemBackgroundColor = Color(0xffffff) + open val lowContrastTextColor = Color(0xe0e0e0) + open val mediumContrastTextColor = Color(0x9E9E9E) + open val statusBarBackgroundColor = Color(0x333333) + open val toolbarBackgroundColor = Color(0xf4f4f4) + open val toolbarColor = Color(0xffffff) - val lowContrastTextColor = Color(0xe0e0e0) - val mediumContrastTextColor = Color(0x9E9E9E) - val highContrastTextColor = Color(0x202020) - - val cardBackgroundColor = Color(0xFFFFFF) - val appBackgroundColor = Color(0xf4f4f4) - val toolbarBackgroundColor = Color(0xf4f4f4) - val statusBarBackgroundColor = Color(0x333333) - - val headerBackgroundColor = Color(0xeeeeee) - val headerBorderColor = Color(0xcccccc) - val headerTextColor = mediumContrastTextColor - - val itemBackgroundColor = Color(0xffffff) - - fun color(paletteIndex: Int): Color { + open fun color(paletteIndex: Int): Color { return when (paletteIndex) { 0 -> Color(0xD32F2F) - 1 -> Color(0x512DA8) + 1 -> Color(0xE64A19) 2 -> Color(0xF57C00) 3 -> Color(0xFF8F00) 4 -> Color(0xF9A825) @@ -58,6 +54,9 @@ abstract class Theme { 14 -> Color(0x8E24AA) 15 -> Color(0xD81B60) 16 -> Color(0x5D4037) + 17 -> Color(0x424242) + 18 -> Color(0x757575) + 19 -> Color(0x9E9E9E) else -> Color(0x000000) } } @@ -68,3 +67,44 @@ abstract class Theme { } class LightTheme : Theme() + +class DarkTheme : Theme() { + override val appBackgroundColor = Color(0x212121) + override val cardBackgroundColor = Color(0x303030) + override val headerBackgroundColor = Color(0x212121) + override val headerBorderColor = Color(0xcccccc) + override val headerTextColor = Color(0x9E9E9E) + override val highContrastTextColor = Color(0xF5F5F5) + override val itemBackgroundColor = Color(0xffffff) + override val lowContrastTextColor = Color(0x424242) + override val mediumContrastTextColor = Color(0x9E9E9E) + override val statusBarBackgroundColor = Color(0x333333) + override val toolbarBackgroundColor = Color(0xf4f4f4) + override val toolbarColor = Color(0xffffff) + + override fun color(paletteIndex: Int): Color { + return when (paletteIndex) { + 0 -> Color(0xEF9A9A) + 1 -> Color(0xFFAB91) + 2 -> Color(0xFFCC80) + 3 -> Color(0xFFECB3) + 4 -> Color(0xFFF59D) + 5 -> Color(0xE6EE9C) + 6 -> Color(0xC5E1A5) + 7 -> Color(0x69F0AE) + 8 -> Color(0x80CBC4) + 9 -> Color(0x80DEEA) + 10 -> Color(0x81D4FA) + 11 -> Color(0x64B5F6) + 12 -> Color(0x9FA8DA) + 13 -> Color(0xB39DDB) + 14 -> Color(0xCE93D8) + 15 -> Color(0xF48FB1) + 16 -> Color(0xBCAAA4) + 17 -> Color(0xF5F5F5) + 18 -> Color(0xE0E0E0) + 19 -> Color(0x9E9E9E) + else -> Color(0xFFFFFF) + } + } +} diff --git a/android/uhabits-core/src/test/java/org/isoron/platform/gui/JavaCanvasTest.kt b/android/uhabits-core/src/test/java/org/isoron/platform/gui/JavaCanvasTest.kt index a7eb11e69..6f2964233 100644 --- a/android/uhabits-core/src/test/java/org/isoron/platform/gui/JavaCanvasTest.kt +++ b/android/uhabits-core/src/test/java/org/isoron/platform/gui/JavaCanvasTest.kt @@ -29,7 +29,7 @@ import java.awt.image.BufferedImage.TYPE_INT_ARGB class JavaCanvasTest { @Test fun run() = runBlocking { - assertRenders("components/CanvasTest.png", createCanvas(500, 400).apply { drawTestImage() }) + assertRenders("views/CanvasTest.png", createCanvas(500, 400).apply { drawTestImage() }) } } @@ -69,9 +69,9 @@ suspend fun assertRenders( width: Int, height: Int, expectedPath: String, - component: Component, + view: View, ) { val canvas = createCanvas(width, height) - component.draw(canvas) + view.draw(canvas) assertRenders(expectedPath, canvas) } diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt index 94e209070..97ac8a601 100644 --- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt +++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/ui/views/BarChartTest.kt @@ -17,19 +17,17 @@ * with this program. If not, see . */ -package org.isoron.uhabits.components +package org.isoron.uhabits.core.ui.views import kotlinx.coroutines.runBlocking import org.isoron.platform.gui.assertRenders import org.isoron.platform.time.JavaLocalDateFormatter import org.isoron.platform.time.LocalDate -import org.isoron.uhabits.core.ui.views.BarChart -import org.isoron.uhabits.core.ui.views.LightTheme import org.junit.Test import java.util.Locale class BarChartTest { - val base = "components/BarChart" + val base = "views/BarChart" val today = LocalDate(2015, 1, 25) val fmt = JavaLocalDateFormatter(Locale.US) val theme = LightTheme() @@ -37,11 +35,20 @@ class BarChartTest { val axis = (0..100).map { today.minus(it) } val series1 = listOf(200.0, 0.0, 150.0, 137.0, 0.0, 0.0, 500.0, 30.0, 100.0, 0.0, 300.0) - @Test - fun testDraw() = runBlocking { + init { component.axis = axis component.series.add(series1) component.colors.add(theme.color(8)) + } + + @Test + fun testDraw() = runBlocking { assertRenders(300, 200, "$base/base.png", component) } + + @Test + fun testDrawWithOffset() = runBlocking { + component.dataOffset = 5 + assertRenders(300, 200, "$base/offset.png", component) + } }