Clean up code after conversions

pull/716/head
Quentin Hibon 5 years ago
parent f882e18be9
commit f1c88797a3

@ -27,8 +27,8 @@ import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice import androidx.test.uiautomator.UiDevice
import junit.framework.TestCase import junit.framework.TestCase
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.hasItems
import org.hamcrest.MatcherAssert import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.core.models.HabitList import org.isoron.uhabits.core.models.HabitList
import org.isoron.uhabits.core.models.ModelFactory import org.isoron.uhabits.core.models.ModelFactory
import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.models.Timestamp
@ -109,9 +109,9 @@ abstract class BaseAndroidTest : TestCase() {
val manager = AppWidgetManager.getInstance(targetContext) val manager = AppWidgetManager.getInstance(targetContext)
val installedProviders: MutableList<ComponentName> = LinkedList() val installedProviders: MutableList<ComponentName> = LinkedList()
for (info in manager.installedProviders) installedProviders.add(info.provider) for (info in manager.installedProviders) installedProviders.add(info.provider)
MatcherAssert.assertThat<List<ComponentName>>( assertThat<List<ComponentName>>(
installedProviders, installedProviders,
CoreMatchers.hasItems(provider) hasItems(provider)
) )
} }
@ -208,7 +208,6 @@ abstract class BaseAndroidTest : TestCase() {
@Throws(Exception::class) @Throws(Exception::class)
fun restoreSystemTime() { fun restoreSystemTime() {
if (savedCalendar == null) throw NullPointerException()
setSystemTime(savedCalendar) setSystemTime(savedCalendar)
} }

@ -99,8 +99,8 @@ open class BaseUserInterfaceTest {
@Throws(Exception::class) @Throws(Exception::class)
protected fun rotateDevice() { protected fun rotateDevice() {
device!!.setOrientationLeft() device.setOrientationLeft()
device!!.setOrientationNatural() device.setOrientationNatural()
} }
companion object { companion object {

@ -34,12 +34,10 @@ import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
import java.util.Random import java.util.Random
import kotlin.math.abs
open class BaseViewTest : BaseAndroidTest() { open class BaseViewTest : BaseAndroidTest() {
var similarityCutoff = 0.00018 var similarityCutoff = 0.00018
override fun setUp() {
super.setUp()
}
@Throws(IOException::class) @Throws(IOException::class)
protected fun assertRenders(view: View, expectedImagePath: String) { protected fun assertRenders(view: View, expectedImagePath: String) {
@ -134,10 +132,10 @@ open class BaseViewTest : BaseAndroidTest() {
if (random.nextInt(4) != 0) continue if (random.nextInt(4) != 0) continue
val argb1 = colorToArgb(b1.getPixel(x, y)) val argb1 = colorToArgb(b1.getPixel(x, y))
val argb2 = colorToArgb(b2.getPixel(x, y)) val argb2 = colorToArgb(b2.getPixel(x, y))
distance += Math.abs(argb1[0] - argb2[0]).toDouble() distance += abs(argb1[0] - argb2[0]).toDouble()
distance += Math.abs(argb1[1] - argb2[1]).toDouble() distance += abs(argb1[1] - argb2[1]).toDouble()
distance += Math.abs(argb1[2] - argb2[2]).toDouble() distance += abs(argb1[2] - argb2[2]).toDouble()
distance += Math.abs(argb1[3] - argb2[3]).toDouble() distance += abs(argb1[3] - argb2[3]).toDouble()
} }
} }
distance /= 255.0 * 16 * b1.width * b1.height distance /= 255.0 * 16 * b1.width * b1.height

@ -20,8 +20,8 @@ package org.isoron.uhabits
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.containsString
import org.hamcrest.MatcherAssert import org.hamcrest.MatcherAssert.assertThat
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import java.io.IOException import java.io.IOException
@ -35,6 +35,6 @@ class HabitsApplicationTest : BaseAndroidTest() {
val msg = "LOGCAT TEST" val msg = "LOGCAT TEST"
RuntimeException(msg).printStackTrace() RuntimeException(msg).printStackTrace()
val log = AndroidBugReporter(targetContext).getLogcat() val log = AndroidBugReporter(targetContext).getLogcat()
MatcherAssert.assertThat(log, CoreMatchers.containsString(msg)) assertThat(log, containsString(msg))
} }
} }

@ -33,16 +33,17 @@ import org.junit.runner.RunWith
class ScoreChartTest : BaseViewTest() { class ScoreChartTest : BaseViewTest() {
private lateinit var habit: Habit private lateinit var habit: Habit
private lateinit var view: ScoreChart private lateinit var view: ScoreChart
@Before @Before
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
fixtures.purgeHabits(habitList) fixtures.purgeHabits(habitList)
habit = fixtures.createLongHabit() habit = fixtures.createLongHabit()
val (scores, bucketSize, _, color) = buildState(habit, prefs.firstWeekdayInt, 0) val state = buildState(habit, prefs.firstWeekdayInt, 0)
view = ScoreChart(targetContext).apply { view = ScoreChart(targetContext).apply {
setScores(scores.toMutableList()) setScores(state.scores)
setColor(color.toFixedAndroidColor()) setColor(state.color.toFixedAndroidColor())
setBucketSize(bucketSize) setBucketSize(state.bucketSize)
} }
measureView(view, dpToPixels(300), dpToPixels(200)) measureView(view, dpToPixels(300), dpToPixels(200))
} }
@ -71,12 +72,8 @@ class ScoreChartTest : BaseViewTest() {
@Test @Test
@Throws(Throwable::class) @Throws(Throwable::class)
fun testRender_withMonthlyBucket() { fun testRender_withMonthlyBucket() {
val (scores, bucketSize) = buildState( val (scores, bucketSize) = buildState(habit, prefs.firstWeekdayInt, 2)
habit, view.setScores(scores)
prefs.firstWeekdayInt,
2
)
view.setScores(scores.toMutableList())
view.setBucketSize(bucketSize) view.setBucketSize(bucketSize)
view.invalidate() view.invalidate()
assertRenders(view, BASE_PATH + "renderMonthly.png") assertRenders(view, BASE_PATH + "renderMonthly.png")
@ -92,13 +89,9 @@ class ScoreChartTest : BaseViewTest() {
@Test @Test
@Throws(Throwable::class) @Throws(Throwable::class)
fun testRender_withYearlyBucket() { fun testRender_withYearlyBucket() {
val (scores, bucketSize) = buildState( val state = buildState(habit, prefs.firstWeekdayInt, 4)
habit, view.setScores(state.scores)
prefs.firstWeekdayInt, view.setBucketSize(state.bucketSize)
4
)
view.setScores(scores.toMutableList())
view.setBucketSize(bucketSize)
view.invalidate() view.invalidate()
assertRenders(view, BASE_PATH + "renderYearly.png") assertRenders(view, BASE_PATH + "renderYearly.png")
} }

@ -23,8 +23,8 @@ import androidx.test.filters.MediumTest
import com.nhaarman.mockitokotlin2.doReturn import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever import com.nhaarman.mockitokotlin2.whenever
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.core.ui.screens.habits.list.HintList import org.isoron.uhabits.core.ui.screens.habits.list.HintList
import org.junit.Before import org.junit.Before
@ -36,6 +36,7 @@ import org.junit.runner.RunWith
class HintViewTest : BaseViewTest() { class HintViewTest : BaseViewTest() {
private lateinit var view: HintView private lateinit var view: HintView
private lateinit var list: HintList private lateinit var list: HintList
@Before @Before
override fun setUp() { override fun setUp() {
super.setUp() super.setUp()
@ -58,10 +59,10 @@ class HintViewTest : BaseViewTest() {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testClick() { fun testClick() {
MatcherAssert.assertThat(view.alpha, CoreMatchers.equalTo(1f)) assertThat(view.alpha, equalTo(1f))
view.performClick() view.performClick()
skipAnimation(view) skipAnimation(view)
MatcherAssert.assertThat(view.alpha, CoreMatchers.equalTo(0f)) assertThat(view.alpha, equalTo(0f))
} }
companion object { companion object {

@ -24,7 +24,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter import org.isoron.uhabits.core.ui.screens.habits.show.views.ScoreCardPresenter.Companion.buildState
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@ -43,13 +43,7 @@ class ScoreCardViewTest : BaseViewTest() {
.from(targetContext) .from(targetContext)
.inflate(R.layout.show_habit, null) .inflate(R.layout.show_habit, null)
.findViewById<View>(R.id.scoreCard) as ScoreCardView .findViewById<View>(R.id.scoreCard) as ScoreCardView
view.setState( view.setState(buildState(habit = habit, firstWeekday = 0, spinnerPosition = 0))
ScoreCardPresenter.buildState(
habit = habit,
firstWeekday = 0,
spinnerPosition = 0,
)
)
measureView(view, 800f, 600f) measureView(view, 800f, 600f)
} }

@ -19,12 +19,11 @@
package org.isoron.uhabits.database package org.isoron.uhabits.database
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import org.hamcrest.MatcherAssert import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual import org.hamcrest.core.IsEqual.equalTo
import org.isoron.uhabits.BaseAndroidTest import org.isoron.uhabits.BaseAndroidTest
import org.isoron.uhabits.core.database.Cursor import org.isoron.uhabits.core.database.Cursor
import org.junit.Test import org.junit.Test
import java.util.HashMap
class AndroidDatabaseTest : BaseAndroidTest() { class AndroidDatabaseTest : BaseAndroidTest() {
private lateinit var db: AndroidDatabase private lateinit var db: AndroidDatabase
@ -37,13 +36,11 @@ class AndroidDatabaseTest : BaseAndroidTest() {
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testInsert() { fun testInsert() {
val map = HashMap<String, Any?>() val map = mapOf(Pair("name", "asd"), Pair("color", null))
map["name"] = "asd"
map["color"] = null
db.insert("test", map) db.insert("test", map)
val c: Cursor = db.query("select * from test") val c: Cursor = db.query("select * from test")
c.moveToNext() c.moveToNext()
assertNull(c.getInt(0)) c.getInt(0)!!
MatcherAssert.assertThat(c.getString(1), IsEqual.equalTo("asd")) assertThat(c.getString(1), equalTo("asd"))
} }
} }

@ -24,7 +24,9 @@ import android.widget.FrameLayout
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest import androidx.test.filters.MediumTest
import org.hamcrest.CoreMatchers import org.hamcrest.CoreMatchers
import org.hamcrest.MatcherAssert import org.hamcrest.CoreMatchers.`is`
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.BaseViewTest import org.isoron.uhabits.BaseViewTest
import org.isoron.uhabits.R import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry import org.isoron.uhabits.core.models.Entry
@ -50,26 +52,26 @@ class CheckmarkWidgetTest : BaseViewTest() {
entries = habit.computedEntries entries = habit.computedEntries
val widget = CheckmarkWidget(targetContext, 0, habit) val widget = CheckmarkWidget(targetContext, 0, habit)
view = convertToView(widget, 150, 200) view = convertToView(widget, 150, 200)
MatcherAssert.assertThat(entries.get(today).value, CoreMatchers.equalTo(Entry.YES_MANUAL)) assertThat(entries.get(today).value, equalTo(Entry.YES_MANUAL))
} }
@Test @Test
@Throws(Exception::class) @Throws(Exception::class)
fun testClick() { fun testClick() {
val button = view.findViewById<View>(R.id.button) as Button val button = view.findViewById<View>(R.id.button) as Button
MatcherAssert.assertThat( assertThat(
button, button,
CoreMatchers.`is`(CoreMatchers.not(CoreMatchers.nullValue())) `is`(CoreMatchers.not(CoreMatchers.nullValue()))
) )
// A better test would be to capture the intent, but it doesn't seem // A better test would be to capture the intent, but it doesn't seem
// possible to capture intents sent to BroadcastReceivers. // possible to capture intents sent to BroadcastReceivers.
button.performClick() button.performClick()
sleep(1000) sleep(1000)
MatcherAssert.assertThat(entries.get(today).value, CoreMatchers.equalTo(Entry.SKIP)) assertThat(entries.get(today).value, equalTo(Entry.SKIP))
button.performClick() button.performClick()
sleep(1000) sleep(1000)
MatcherAssert.assertThat(entries.get(today).value, CoreMatchers.equalTo(Entry.NO)) assertThat(entries.get(today).value, equalTo(Entry.NO))
} }
@Test @Test

@ -53,10 +53,6 @@ constructor(
} }
} }
// override fun getCurrentTheme(): Theme {
// return currentTheme
// }
override fun applyDarkTheme() { override fun applyDarkTheme() {
currentTheme = DarkTheme() currentTheme = DarkTheme()
context.setTheme(R.style.AppBaseThemeDark) context.setTheme(R.style.AppBaseThemeDark)

@ -62,7 +62,7 @@ class ScoreChart : ScrollableChart {
private var nColumns = 0 private var nColumns = 0
private var textColor = 0 private var textColor = 0
private var gridColor = 0 private var gridColor = 0
private var scores: MutableList<Score>? = null private var scores: List<Score>? = null
private var primaryColor = 0 private var primaryColor = 0
@Deprecated("") @Deprecated("")
@ -113,7 +113,7 @@ class ScoreChart : ScrollableChart {
postInvalidate() postInvalidate()
} }
fun setScores(scores: MutableList<Score>) { fun setScores(scores: List<Score>) {
this.scores = scores this.scores = scores
postInvalidate() postInvalidate()
} }

@ -37,10 +37,10 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
private set private set
private var scrollerBucketSize = 1 private var scrollerBucketSize = 1
private var direction = 1 private var direction = 1
private var detector: GestureDetector? = null private lateinit var detector: GestureDetector
private var scroller: Scroller? = null private lateinit var scroller: Scroller
private var scrollAnimator: ValueAnimator? = null private lateinit var scrollAnimator: ValueAnimator
private var scrollController: ScrollController? = null private lateinit var scrollController: ScrollController
private var maxDataOffset = 10000 private var maxDataOffset = 10000
constructor(context: Context?) : super(context) { constructor(context: Context?) : super(context) {
@ -52,11 +52,11 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
} }
override fun onAnimationUpdate(animation: ValueAnimator) { override fun onAnimationUpdate(animation: ValueAnimator) {
if (!scroller!!.isFinished) { if (!scroller.isFinished) {
scroller!!.computeScrollOffset() scroller.computeScrollOffset()
updateDataOffset() updateDataOffset()
} else { } else {
scrollAnimator!!.cancel() scrollAnimator.cancel()
} }
} }
@ -70,9 +70,9 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
velocityX: Float, velocityX: Float,
velocityY: Float velocityY: Float
): Boolean { ): Boolean {
scroller!!.fling( scroller.fling(
scroller!!.currX, scroller.currX,
scroller!!.currY, scroller.currY,
direction * velocityX.toInt() / 2, direction * velocityX.toInt() / 2,
0, 0,
0, 0,
@ -81,13 +81,13 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
0 0
) )
invalidate() invalidate()
scrollAnimator!!.duration = scroller!!.duration.toLong() scrollAnimator.duration = scroller.duration.toLong()
scrollAnimator!!.start() scrollAnimator.start()
return false return false
} }
private val maxX: Int private val maxX: Int
private get() = maxDataOffset * scrollerBucketSize get() = maxDataOffset * scrollerBucketSize
public override fun onRestoreInstanceState(state: Parcelable) { public override fun onRestoreInstanceState(state: Parcelable) {
if (state !is BundleSavedState) { if (state !is BundleSavedState) {
@ -99,16 +99,16 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
direction = state.bundle.getInt("direction") direction = state.bundle.getInt("direction")
dataOffset = state.bundle.getInt("dataOffset") dataOffset = state.bundle.getInt("dataOffset")
maxDataOffset = state.bundle.getInt("maxDataOffset") maxDataOffset = state.bundle.getInt("maxDataOffset")
scroller!!.startScroll(0, 0, x, y, 0) scroller.startScroll(0, 0, x, y, 0)
scroller!!.computeScrollOffset() scroller.computeScrollOffset()
super.onRestoreInstanceState(state.superState) super.onRestoreInstanceState(state.superState)
} }
public override fun onSaveInstanceState(): Parcelable? { public override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState() val superState = super.onSaveInstanceState()
val bundle = Bundle().apply { val bundle = Bundle().apply {
putInt("x", scroller!!.currX) putInt("x", scroller.currX)
putInt("y", scroller!!.currY) putInt("y", scroller.currY)
putInt("dataOffset", dataOffset) putInt("dataOffset", dataOffset)
putInt("direction", direction) putInt("direction", direction)
putInt("maxDataOffset", maxDataOffset) putInt("maxDataOffset", maxDataOffset)
@ -124,15 +124,15 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
parent?.requestDisallowInterceptTouchEvent(true) parent?.requestDisallowInterceptTouchEvent(true)
} }
dx *= -direction dx *= -direction
dx = min(dx, (maxX - scroller!!.currX).toFloat()) dx = min(dx, (maxX - scroller.currX).toFloat())
scroller!!.startScroll( scroller.startScroll(
scroller!!.currX, scroller.currX,
scroller!!.currY, scroller.currY,
dx.toInt(), dx.toInt(),
dy.toInt(), dy.toInt(),
0 0
) )
scroller!!.computeScrollOffset() scroller.computeScrollOffset()
updateDataOffset() updateDataOffset()
return true return true
} }
@ -143,7 +143,7 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
} }
override fun onTouchEvent(event: MotionEvent): Boolean { override fun onTouchEvent(event: MotionEvent): Boolean {
return detector!!.onTouchEvent(event) return detector.onTouchEvent(event)
} }
fun setScrollDirection(direction: Int) { fun setScrollDirection(direction: Int) {
@ -155,11 +155,11 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
fun setMaxDataOffset(maxDataOffset: Int) { fun setMaxDataOffset(maxDataOffset: Int) {
this.maxDataOffset = maxDataOffset this.maxDataOffset = maxDataOffset
dataOffset = min(dataOffset, maxDataOffset) dataOffset = min(dataOffset, maxDataOffset)
scrollController!!.onDataOffsetChanged(dataOffset) scrollController.onDataOffsetChanged(dataOffset)
postInvalidate() postInvalidate()
} }
fun setScrollController(scrollController: ScrollController?) { fun setScrollController(scrollController: ScrollController) {
this.scrollController = scrollController this.scrollController = scrollController
} }
@ -177,18 +177,18 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
} }
fun reset() { fun reset() {
scroller!!.finalX = 0 scroller.finalX = 0
scroller!!.computeScrollOffset() scroller.computeScrollOffset()
updateDataOffset() updateDataOffset()
} }
private fun updateDataOffset() { private fun updateDataOffset() {
var newDataOffset = scroller!!.currX / scrollerBucketSize var newDataOffset = scroller.currX / scrollerBucketSize
newDataOffset = max(0, newDataOffset) newDataOffset = max(0, newDataOffset)
newDataOffset = min(maxDataOffset, newDataOffset) newDataOffset = min(maxDataOffset, newDataOffset)
if (newDataOffset != dataOffset) { if (newDataOffset != dataOffset) {
dataOffset = newDataOffset dataOffset = newDataOffset
scrollController!!.onDataOffsetChanged(dataOffset) scrollController.onDataOffsetChanged(dataOffset)
postInvalidate() postInvalidate()
} }
} }

@ -22,7 +22,6 @@ package org.isoron.uhabits.activities.habits.list.views
import android.content.Context import android.content.Context
import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED
import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.LOLLIPOP
import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.M
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
@ -159,7 +158,7 @@ class HabitCardView(
gravity = Gravity.CENTER_VERTICAL gravity = Gravity.CENTER_VERTICAL
orientation = LinearLayout.HORIZONTAL orientation = LinearLayout.HORIZONTAL
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT) layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
if (SDK_INT >= LOLLIPOP) elevation = dp(1f) elevation = dp(1f)
addView(scoreRing) addView(scoreRing)
addView(label) addView(label)
@ -167,7 +166,6 @@ class HabitCardView(
addView(numberPanel) addView(numberPanel)
setOnTouchListener { v, event -> setOnTouchListener { v, event ->
if (SDK_INT >= LOLLIPOP)
v.background.setHotspot(event.x, event.y) v.background.setHotspot(event.x, event.y)
false false
} }
@ -247,7 +245,7 @@ class HabitCardView(
private fun triggerRipple(x: Float, y: Float) { private fun triggerRipple(x: Float, y: Float) {
val background = innerFrame.background val background = innerFrame.background
if (SDK_INT >= LOLLIPOP) background.setHotspot(x, y) background.setHotspot(x, y)
background.state = intArrayOf( background.state = intArrayOf(
android.R.attr.state_pressed, android.R.attr.state_pressed,
android.R.attr.state_enabled android.R.attr.state_enabled
@ -256,14 +254,6 @@ class HabitCardView(
} }
private fun updateBackground(isSelected: Boolean) { private fun updateBackground(isSelected: Boolean) {
if (SDK_INT < LOLLIPOP) {
val background = when (isSelected) {
true -> sres.getDrawable(R.attr.selectedBackground)
false -> sres.getDrawable(R.attr.cardBackground)
}
innerFrame.setBackgroundDrawable(background)
return
}
val background = when (isSelected) { val background = when (isSelected) {
true -> R.drawable.selected_box true -> R.drawable.selected_box

@ -25,8 +25,6 @@ import android.graphics.Color
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF import android.graphics.RectF
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES.LOLLIPOP
import android.text.TextPaint import android.text.TextPaint
import android.view.View.MeasureSpec.EXACTLY import android.view.View.MeasureSpec.EXACTLY
import org.isoron.uhabits.R import org.isoron.uhabits.R
@ -60,7 +58,7 @@ class HeaderView(
init { init {
setScrollerBucketSize(dim(R.dimen.checkmarkWidth).toInt()) setScrollerBucketSize(dim(R.dimen.checkmarkWidth).toInt())
setBackgroundColor(sres.getColor(R.attr.headerBackgroundColor)) setBackgroundColor(sres.getColor(R.attr.headerBackgroundColor))
if (SDK_INT >= LOLLIPOP) elevation = dp(2.0f) elevation = dp(2.0f)
} }
override fun atMidnight() { override fun atMidnight() {

@ -161,16 +161,20 @@ class NumberButtonView(
val label: String val label: String
val typeface: Typeface val typeface: Typeface
if (value >= 0) { when {
value >= 0 -> {
label = value.toShortString() label = value.toShortString()
typeface = BOLD_TYPEFACE typeface = BOLD_TYPEFACE
} else if (preferences.areQuestionMarksEnabled()) { }
preferences.areQuestionMarksEnabled() -> {
label = resources.getString(R.string.fa_question) label = resources.getString(R.string.fa_question)
typeface = getFontAwesome() typeface = getFontAwesome()
} else { }
else -> {
label = "0" label = "0"
typeface = BOLD_TYPEFACE typeface = BOLD_TYPEFACE
} }
}
pBold.color = activeColor pBold.color = activeColor
pBold.typeface = typeface pBold.typeface = typeface

@ -36,7 +36,7 @@ class ScoreCardView(context: Context, attrs: AttributeSet) : LinearLayout(contex
val androidColor = state.color.toThemedAndroidColor(context) val androidColor = state.color.toThemedAndroidColor(context)
binding.title.setTextColor(androidColor) binding.title.setTextColor(androidColor)
binding.spinner.setSelection(state.spinnerPosition) binding.spinner.setSelection(state.spinnerPosition)
binding.scoreView.setScores(state.scores.toMutableList()) binding.scoreView.setScores(state.scores)
binding.scoreView.reset() binding.scoreView.reset()
binding.scoreView.setBucketSize(state.bucketSize) binding.scoreView.setBucketSize(state.bucketSize)
binding.scoreView.setColor(androidColor) binding.scoreView.setColor(androidColor)

@ -75,7 +75,6 @@ class AndroidTaskRunner : TaskRunner {
} }
override fun onPreExecute() { override fun onPreExecute() {
// isCancelled = task.isCanceled
if (isCancelled) return if (isCancelled) return
for (l in listeners) l.onTaskStarted(task) for (l in listeners) l.onTaskStarted(task)
activeTasks.add(this) activeTasks.add(this)

@ -52,7 +52,7 @@ class ScoreWidget(
setIsTransparencyEnabled(true) setIsTransparencyEnabled(true)
setBucketSize(viewModel.bucketSize) setBucketSize(viewModel.bucketSize)
setColor(habit.color.toThemedAndroidColor(context)) setColor(habit.color.toThemedAndroidColor(context))
setScores(viewModel.scores.toMutableList()) setScores(viewModel.scores)
} }
} }

@ -30,13 +30,13 @@ import javax.annotation.concurrent.ThreadSafe
@ThreadSafe @ThreadSafe
abstract class HabitList : Iterable<Habit> { abstract class HabitList : Iterable<Habit> {
val observable: ModelObservable val observable: ModelObservable
@JvmField @JvmField
protected val filter: HabitMatcher protected val filter: HabitMatcher
/** /**
* Creates a new HabitList. * Creates a new HabitList.
* *
*
* Depending on the implementation, this list can either be empty or be * Depending on the implementation, this list can either be empty or be
* populated by some pre-existing habits, for example, from a certain * populated by some pre-existing habits, for example, from a certain
* database. * database.
@ -54,7 +54,6 @@ abstract class HabitList : Iterable<Habit> {
/** /**
* Inserts a new habit in the list. * Inserts a new habit in the list.
* *
*
* If the id of the habit is null, the list will assign it a new id, which * If the id of the habit is null, the list will assign it a new id, which
* is guaranteed to be unique in the scope of the list. If id is not null, * is guaranteed to be unique in the scope of the list. If id is not null,
* the caller should make sure that the list does not already contain * the caller should make sure that the list does not already contain
@ -115,7 +114,6 @@ abstract class HabitList : Iterable<Habit> {
/** /**
* Removes the given habit from the list. * Removes the given habit from the list.
* *
*
* If the given habit is not in the list, does nothing. * If the given habit is not in the list, does nothing.
* *
* @param h the habit to be removed. * @param h the habit to be removed.
@ -151,7 +149,6 @@ abstract class HabitList : Iterable<Habit> {
/** /**
* Notifies the list that a certain list of habits has been modified. * Notifies the list that a certain list of habits has been modified.
* *
*
* Depending on the implementation, this operation might trigger a write to * Depending on the implementation, this operation might trigger a write to
* disk, or do nothing at all. To make sure that the habits get persisted, * disk, or do nothing at all. To make sure that the habits get persisted,
* this operation must be called. * this operation must be called.
@ -163,7 +160,6 @@ abstract class HabitList : Iterable<Habit> {
/** /**
* Notifies the list that a certain habit has been modified. * Notifies the list that a certain habit has been modified.
* *
*
* See [.update] for more details. * See [.update] for more details.
* *
* @param habit the habit that has been modified. * @param habit the habit that has been modified.
@ -212,6 +208,14 @@ abstract class HabitList : Iterable<Habit> {
abstract fun resort() abstract fun resort()
enum class Order { enum class Order {
BY_NAME_ASC, BY_NAME_DESC, BY_COLOR_ASC, BY_COLOR_DESC, BY_SCORE_ASC, BY_SCORE_DESC, BY_STATUS_ASC, BY_STATUS_DESC, BY_POSITION BY_NAME_ASC,
BY_NAME_DESC,
BY_COLOR_ASC,
BY_COLOR_DESC,
BY_SCORE_ASC,
BY_SCORE_DESC,
BY_STATUS_ASC,
BY_STATUS_DESC,
BY_POSITION
} }
} }

@ -151,16 +151,18 @@ class MemoryHabitList : HabitList {
} }
val statusComparatorAsc = val statusComparatorAsc =
Comparator { h1: Habit, h2: Habit -> statusComparatorDesc.compare(h2, h1) } Comparator { h1: Habit, h2: Habit -> statusComparatorDesc.compare(h2, h1) }
if (order === Order.BY_POSITION) return positionComparator return when {
if (order === Order.BY_NAME_ASC) return nameComparatorAsc order === Order.BY_POSITION -> positionComparator
if (order === Order.BY_NAME_DESC) return nameComparatorDesc order === Order.BY_NAME_ASC -> nameComparatorAsc
if (order === Order.BY_COLOR_ASC) return colorComparatorAsc order === Order.BY_NAME_DESC -> nameComparatorDesc
if (order === Order.BY_COLOR_DESC) return colorComparatorDesc order === Order.BY_COLOR_ASC -> colorComparatorAsc
if (order === Order.BY_SCORE_DESC) return scoreComparatorDesc order === Order.BY_COLOR_DESC -> colorComparatorDesc
if (order === Order.BY_SCORE_ASC) return scoreComparatorAsc order === Order.BY_SCORE_DESC -> scoreComparatorDesc
if (order === Order.BY_STATUS_DESC) return statusComparatorDesc order === Order.BY_SCORE_ASC -> scoreComparatorAsc
if (order === Order.BY_STATUS_ASC) return statusComparatorAsc order === Order.BY_STATUS_DESC -> statusComparatorDesc
throw IllegalStateException() order === Order.BY_STATUS_ASC -> statusComparatorAsc
else -> throw IllegalStateException()
}
} }
@Synchronized @Synchronized

@ -1,23 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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/>.
*/
/**
* Provides in-memory implementation of core models.
*/
package org.isoron.uhabits.core.models.memory;

@ -1,23 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* 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/>.
*/
/**
* Provides SQLite implementations of the core models.
*/
package org.isoron.uhabits.core.models.sqlite;

@ -29,7 +29,7 @@ import org.isoron.uhabits.core.models.sqlite.SQLiteEntryList
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
class HabitFixtures(private val modelFactory: ModelFactory, private val habitList: HabitList) { class HabitFixtures(private val modelFactory: ModelFactory, private val habitList: HabitList) {
var NON_DAILY_HABIT_CHECKS = booleanArrayOf( private var NON_DAILY_HABIT_CHECKS = booleanArrayOf(
true, false, false, true, true, true, false, false, true, true true, false, false, true, true, true, false, false, true, true
) )

@ -123,7 +123,14 @@ open class ListHabitsBehavior @Inject constructor(
} }
enum class Message { enum class Message {
COULD_NOT_EXPORT, IMPORT_SUCCESSFUL, IMPORT_FAILED, DATABASE_REPAIRED, COULD_NOT_GENERATE_BUG_REPORT, FILE_NOT_RECOGNIZED, SYNC_ENABLED, SYNC_KEY_ALREADY_INSTALLED COULD_NOT_EXPORT,
IMPORT_SUCCESSFUL,
IMPORT_FAILED,
DATABASE_REPAIRED,
COULD_NOT_GENERATE_BUG_REPORT,
FILE_NOT_RECOGNIZED,
SYNC_ENABLED,
SYNC_KEY_ALREADY_INSTALLED
} }
interface BugReporter { interface BugReporter {

@ -37,7 +37,7 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
var commandRunner: CommandRunner var commandRunner: CommandRunner
) { ) {
fun canArchive(): Boolean { fun canArchive(): Boolean {
for ((_, _, _, _, isArchived) in adapter.selected) if (isArchived) return false for (habit in adapter.selected) if (habit.isArchived) return false
return true return true
} }
@ -46,7 +46,7 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
} }
fun canUnarchive(): Boolean { fun canUnarchive(): Boolean {
for ((_, _, _, _, isArchived) in adapter.selected) if (!isArchived) return false for (habit in adapter.selected) if (!habit.isArchived) return false
return true return true
} }
@ -56,23 +56,21 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
} }
fun onChangeColor() { fun onChangeColor() {
val selected = adapter.selected val (color) = adapter.selected[0]
val (color) = selected[0]
screen.showColorPicker(color) { selectedColor: PaletteColor -> screen.showColorPicker(color) { selectedColor: PaletteColor ->
commandRunner.run(ChangeHabitColorCommand(habitList, selected, selectedColor)) commandRunner.run(ChangeHabitColorCommand(habitList, adapter.selected, selectedColor))
adapter.clearSelection() adapter.clearSelection()
} }
} }
fun onDeleteHabits() { fun onDeleteHabits() {
val selected = adapter.selected
screen.showDeleteConfirmationScreen( screen.showDeleteConfirmationScreen(
{ {
adapter.performRemove(selected) adapter.performRemove(adapter.selected)
commandRunner.run(DeleteHabitsCommand(habitList, selected)) commandRunner.run(DeleteHabitsCommand(habitList, adapter.selected))
adapter.clearSelection() adapter.clearSelection()
}, },
selected.size adapter.selected.size
) )
} }

@ -18,19 +18,20 @@
*/ */
package org.isoron.uhabits.core.database package org.isoron.uhabits.core.database
import junit.framework.Assert.assertNull
import org.apache.commons.lang3.builder.EqualsBuilder import org.apache.commons.lang3.builder.EqualsBuilder
import org.apache.commons.lang3.builder.HashCodeBuilder import org.apache.commons.lang3.builder.HashCodeBuilder
import org.apache.commons.lang3.builder.ToStringBuilder import org.apache.commons.lang3.builder.ToStringBuilder
import org.hamcrest.MatcherAssert import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.core.IsEqual import org.hamcrest.core.IsEqual.equalTo
import org.isoron.uhabits.core.BaseUnitTest import org.isoron.uhabits.core.BaseUnitTest
import org.junit.Assert
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
class RepositoryTest : BaseUnitTest() { class RepositoryTest : BaseUnitTest() {
private lateinit var repository: Repository<ThingRecord> private lateinit var repository: Repository<ThingRecord>
private lateinit var db: Database private lateinit var db: Database
@Before @Before
@Throws(Exception::class) @Throws(Exception::class)
override fun setUp() { override fun setUp() {
@ -54,11 +55,10 @@ class RepositoryTest : BaseUnitTest() {
"values (10, 20, 'hello', 8.0)" "values (10, 20, 'hello', 8.0)"
) )
val record = repository.find(10L) val record = repository.find(10L)
Assert.assertNotNull(record) assertThat(record!!.id, equalTo(10L))
MatcherAssert.assertThat(record!!.id, IsEqual.equalTo(10L)) assertThat(record.color, equalTo(20))
MatcherAssert.assertThat(record.color, IsEqual.equalTo(20)) assertThat(record.name, equalTo("hello"))
MatcherAssert.assertThat(record.name, IsEqual.equalTo("hello")) assertThat(record.score, equalTo(8.0))
MatcherAssert.assertThat(record.score, IsEqual.equalTo(8.0))
} }
@Test @Test
@ -71,11 +71,11 @@ class RepositoryTest : BaseUnitTest() {
score = 5.0 score = 5.0
} }
repository.save(record) repository.save(record)
MatcherAssert.assertThat(record, IsEqual.equalTo(repository.find(50L))) assertThat(record, equalTo(repository.find(50L)))
record.name = "world" record.name = "world"
record.score = 128.0 record.score = 128.0
repository.save(record) repository.save(record)
MatcherAssert.assertThat(record, IsEqual.equalTo(repository.find(50L))) assertThat(record, equalTo(repository.find(50L)))
} }
@Test @Test
@ -88,9 +88,8 @@ class RepositoryTest : BaseUnitTest() {
} }
repository.save(record) repository.save(record)
val retrieved = repository.find(record.id!!) val retrieved = repository.find(record.id!!)
Assert.assertNotNull(retrieved) assertNull(retrieved!!.name)
Assert.assertNull(retrieved!!.name) assertThat(record, equalTo(retrieved))
MatcherAssert.assertThat(record, IsEqual.equalTo(retrieved))
} }
@Test @Test
@ -108,8 +107,8 @@ class RepositoryTest : BaseUnitTest() {
score = 2.0 score = 2.0
} }
repository.save(r2) repository.save(r2)
MatcherAssert.assertThat(r1.id, IsEqual.equalTo(1L)) assertThat(r1.id, equalTo(1L))
MatcherAssert.assertThat(r2.id, IsEqual.equalTo(2L)) assertThat(r2.id, equalTo(2L))
} }
@Test @Test
@ -128,14 +127,14 @@ class RepositoryTest : BaseUnitTest() {
} }
repository.save(rec2) repository.save(rec2)
val id = rec1.id!! val id = rec1.id!!
MatcherAssert.assertThat(rec1, IsEqual.equalTo(repository.find(id))) assertThat(rec1, equalTo(repository.find(id)))
MatcherAssert.assertThat(rec2, IsEqual.equalTo(repository.find(rec2.id!!))) assertThat(rec2, equalTo(repository.find(rec2.id!!)))
repository.remove(rec1) repository.remove(rec1)
MatcherAssert.assertThat(rec1.id, IsEqual.equalTo(null)) assertThat(rec1.id, equalTo(null))
Assert.assertNull(repository.find(id)) assertNull(repository.find(id))
MatcherAssert.assertThat(rec2, IsEqual.equalTo(repository.find(rec2.id!!))) assertThat(rec2, equalTo(repository.find(rec2.id!!)))
repository.remove(rec1) // should have no effect repository.remove(rec1) // should have no effect
Assert.assertNull(repository.find(id)) assertNull(repository.find(id))
} }
@Table(name = "tests") @Table(name = "tests")

Loading…
Cancel
Save