mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-08 10:08:51 -06:00
Compare commits
1 Commits
hiqua-patc
...
830e28ca8e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
830e28ca8e |
1
.github/dependabot.yml
vendored
1
.github/dependabot.yml
vendored
@@ -4,7 +4,6 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
|
||||
6
.github/workflows/main.yml
vendored
6
.github/workflows/main.yml
vendored
@@ -12,17 +12,17 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Check out source code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Build project
|
||||
run: ./build.sh build
|
||||
|
||||
- name: Run Android tests
|
||||
run: ./build.sh android-tests-parallel 28 29 30 32 33 34
|
||||
run: ./build.sh android-tests-parallel 28 29 30 31 32 33
|
||||
|
||||
- name: Upload artifacts
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: build
|
||||
path: |
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -17,4 +17,3 @@ node_modules
|
||||
*xcuserdata*
|
||||
*.sketch
|
||||
crowdin.yml
|
||||
kotlin-js-store
|
||||
|
||||
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,22 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [2.2.0] -- 2024-01-30
|
||||
### Added
|
||||
- Add support for Android 14 (@iSoron, @hiqua)
|
||||
- Allow user to change app language (@leondzn)
|
||||
|
||||
### Fixed
|
||||
- Implement workaround to make notifications non-dismissible in Android 14 (@iSoron, #1872)
|
||||
- Fix splash screen background color in dark mode (@SIKV, #1888)
|
||||
|
||||
## [2.1.3] -- 2023-08-28
|
||||
### Fixed
|
||||
- Use text input on Samsung devices (@iSoron, #1719)
|
||||
- Prevent crash if alarm permission is revoked (@iSoron)
|
||||
- Adjust widget colors (@iSoron)
|
||||
- Fix bug preventing screens from updating at midnight (@iSoron)
|
||||
- Fix skip button in locales that use comma instead of dot (@iSoron, #1721)
|
||||
|
||||
## [2.1.2] -- 2023-05-26
|
||||
### Fixed
|
||||
- Fix bug that caused widget to enter checkmark on wrong date (@iSoron, #1541)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
plugins {
|
||||
val kotlinVersion = "1.9.22"
|
||||
id("com.android.application") version "8.1.4" apply (false)
|
||||
val kotlinVersion = "1.7.21"
|
||||
id("com.android.application") version ("7.4.2") apply (false)
|
||||
id("org.jetbrains.kotlin.android") version kotlinVersion apply (false)
|
||||
id("org.jetbrains.kotlin.kapt") version kotlinVersion apply (false)
|
||||
id("org.jetbrains.kotlin.android.extensions") version kotlinVersion apply (false)
|
||||
id("org.jetbrains.kotlin.multiplatform") version kotlinVersion apply (false)
|
||||
id("org.jlleitschuh.gradle.ktlint") version "11.6.1"
|
||||
id("org.jlleitschuh.gradle.ktlint") version "11.4.2"
|
||||
}
|
||||
|
||||
apply {
|
||||
|
||||
2
build.sh
2
build.sh
@@ -181,7 +181,7 @@ android_test() {
|
||||
OUT_INSTRUMENT=${ANDROID_OUTPUTS_DIR}/instrument-${API}.txt
|
||||
OUT_LOGCAT=${ANDROID_OUTPUTS_DIR}/logcat-${API}.txt
|
||||
FAILED_TESTS=""
|
||||
for i in {1..10}; do
|
||||
for i in {1..5}; do
|
||||
log_info "Running $size instrumented tests (attempt $i)..."
|
||||
$ADB shell am instrument \
|
||||
-r -e coverage true -e size "$size" $FAILED_TESTS \
|
||||
|
||||
@@ -3,6 +3,3 @@ org.gradle.daemon=true
|
||||
org.gradle.jvmargs=-Xms2048m -Xmx2048m
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
android.nonTransitiveRClass=false
|
||||
android.nonFinalResIds=false
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("com.github.triplet.play") version "3.8.6"
|
||||
id("com.android.application") version "8.1.4"
|
||||
id("com.github.triplet.play") version "3.7.0"
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
id("org.jetbrains.kotlin.kapt")
|
||||
id("org.jetbrains.kotlin.android.extensions")
|
||||
id("org.jlleitschuh.gradle.ktlint")
|
||||
}
|
||||
|
||||
@@ -29,27 +30,15 @@ tasks.compileLint {
|
||||
dependsOn("updateTranslators")
|
||||
}
|
||||
|
||||
/*
|
||||
Added on top of kotlinOptions to work around this issue:
|
||||
https://youtrack.jetbrains.com/issue/KTIJ-24311/task-current-target-is-17-and-kaptGenerateStubsProductionDebugKotlin-task-current-target-is-1.8-jvm-target-compatibility-should#focus=Comments-27-6798448.0-0
|
||||
Updating gradle might fix this, so try again in the future to remove this and run:
|
||||
./gradlew --rerun-tasks :uhabits-android:kaptGenerateStubsReleaseKotlin
|
||||
If this doesn't produce any warning, try to remove it.
|
||||
*/
|
||||
kotlin {
|
||||
jvmToolchain(11)
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
namespace = "org.isoron.uhabits"
|
||||
compileSdk = 34
|
||||
compileSdk = 32
|
||||
|
||||
defaultConfig {
|
||||
versionCode = 20200
|
||||
versionName = "2.2.0"
|
||||
minSdk = 28
|
||||
targetSdk = 34
|
||||
targetSdk = 31
|
||||
applicationId = "org.isoron.uhabits"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -81,11 +70,8 @@ android {
|
||||
|
||||
compileOptions {
|
||||
isCoreLibraryDesugaringEnabled = true
|
||||
targetCompatibility(JavaVersion.VERSION_11)
|
||||
sourceCompatibility(JavaVersion.VERSION_11)
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_11.toString()
|
||||
targetCompatibility(JavaVersion.VERSION_1_8)
|
||||
sourceCompatibility(JavaVersion.VERSION_1_8)
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
@@ -94,9 +80,9 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val daggerVersion = "2.51.1"
|
||||
val kotlinVersion = "1.9.22"
|
||||
val kxCoroutinesVersion = "1.7.3"
|
||||
val daggerVersion = "2.46"
|
||||
val kotlinVersion = "1.7.21"
|
||||
val kxCoroutinesVersion = "1.6.4"
|
||||
val ktorVersion = "1.6.8"
|
||||
val espressoVersion = "3.5.1"
|
||||
|
||||
@@ -106,17 +92,17 @@ dependencies {
|
||||
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito:2.28.3")
|
||||
androidTestImplementation("io.ktor:ktor-client-mock:$ktorVersion")
|
||||
androidTestImplementation("io.ktor:ktor-jackson:$ktorVersion")
|
||||
androidTestImplementation("androidx.annotation:annotation:1.7.1")
|
||||
androidTestImplementation("androidx.annotation:annotation:1.5.0")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
|
||||
androidTestImplementation("androidx.test:rules:1.5.0")
|
||||
androidTestImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||
androidTestImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
|
||||
compileOnly("javax.annotation:jsr250-api:1.0")
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
|
||||
implementation("com.github.AppIntro:AppIntro:6.3.1")
|
||||
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
|
||||
implementation("com.github.AppIntro:AppIntro:6.2.0")
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
implementation("com.google.dagger:dagger:$daggerVersion")
|
||||
implementation("com.google.guava:guava:33.1.0-android")
|
||||
implementation("com.google.guava:guava:31.1-android")
|
||||
implementation("io.ktor:ktor-client-android:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-client-jackson:$ktorVersion")
|
||||
@@ -124,18 +110,17 @@ dependencies {
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kxCoroutinesVersion")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kxCoroutinesVersion")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.appcompat:appcompat:1.5.1")
|
||||
implementation("androidx.legacy:legacy-preference-v14:1.0.0")
|
||||
implementation("androidx.legacy:legacy-support-v4:1.0.0")
|
||||
implementation("com.google.android.material:material:1.11.0")
|
||||
implementation("com.opencsv:opencsv:5.9")
|
||||
implementation("nl.dionsegijn:konfetti-xml:2.0.2")
|
||||
implementation("com.google.android.material:material:1.8.0")
|
||||
implementation("com.opencsv:opencsv:5.7.1")
|
||||
implementation(project(":uhabits-core"))
|
||||
kapt("com.google.dagger:dagger-compiler:$daggerVersion")
|
||||
kaptAndroidTest("com.google.dagger:dagger-compiler:$daggerVersion")
|
||||
testImplementation("com.google.dagger:dagger:$daggerVersion")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
|
||||
}
|
||||
|
||||
kapt {
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import dagger.Component
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
@@ -34,7 +35,6 @@ import org.isoron.uhabits.inject.ActivityScope
|
||||
import org.isoron.uhabits.inject.HabitModule
|
||||
import org.isoron.uhabits.inject.HabitsActivityModule
|
||||
import org.isoron.uhabits.inject.HabitsApplicationComponent
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@Module
|
||||
class TestModule {
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.isoron.uhabits.acceptance.steps
|
||||
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.Espresso
|
||||
@@ -32,11 +33,11 @@ import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.uiautomator.By
|
||||
import androidx.test.uiautomator.UiSelector
|
||||
import androidx.test.uiautomator.Until
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.isoron.uhabits.BaseUserInterfaceTest
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.activities.habits.list.ListHabitsActivity
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
object CommonSteps : BaseUserInterfaceTest() {
|
||||
fun pressBack() {
|
||||
@@ -132,7 +133,7 @@ object CommonSteps : BaseUserInterfaceTest() {
|
||||
}
|
||||
|
||||
@Throws(Exception::class)
|
||||
fun verifyOpensWebsite(url: String) {
|
||||
fun verifyOpensWebsite(url: String?) {
|
||||
var browserPkg = "org.chromium.webview_shell"
|
||||
if (SDK_INT <= Build.VERSION_CODES.M) {
|
||||
browserPkg = "com.android.browser"
|
||||
@@ -147,19 +148,15 @@ object CommonSteps : BaseUserInterfaceTest() {
|
||||
Screen.LIST_HABITS ->
|
||||
Espresso.onView(ViewMatchers.withClassName(CoreMatchers.endsWith("ListHabitsRootView")))
|
||||
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
||||
|
||||
Screen.SHOW_HABIT ->
|
||||
Espresso.onView(ViewMatchers.withId(R.id.subtitleCard))
|
||||
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
||||
|
||||
Screen.EDIT_HABIT ->
|
||||
Espresso.onView(ViewMatchers.withId(R.id.questionInput))
|
||||
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
||||
|
||||
Screen.SELECT_HABIT_TYPE ->
|
||||
Espresso.onView(ViewMatchers.withText(R.string.yes_or_no_example))
|
||||
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
|
||||
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ package org.isoron.uhabits.acceptance.steps
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import androidx.test.uiautomator.UiScrollable
|
||||
import androidx.test.uiautomator.UiSelector
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.isoron.uhabits.BaseUserInterfaceTest
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
|
||||
object WidgetSteps {
|
||||
@Throws(Exception::class)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.isoron.uhabits.activities.common.views
|
||||
|
||||
import android.view.MotionEvent
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
@@ -53,8 +52,7 @@ class FrequencyChartTest : BaseViewTest() {
|
||||
@Test
|
||||
@Throws(Throwable::class)
|
||||
fun testRender_withDataOffset() {
|
||||
val e = MotionEvent.obtain(0, 0, 0, 0f, 0f, 0)
|
||||
view.onScroll(e, e, -dpToPixels(150), 0f)
|
||||
view.onScroll(null, null, -dpToPixels(150), 0f)
|
||||
view.invalidate()
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png")
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.isoron.uhabits.activities.common.views
|
||||
|
||||
import android.view.MotionEvent
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
@@ -64,8 +63,7 @@ class ScoreChartTest : BaseViewTest() {
|
||||
@Test
|
||||
@Throws(Throwable::class)
|
||||
fun testRender_withDataOffset() {
|
||||
val e = MotionEvent.obtain(0, 0, 0, 0f, 0f, 0)
|
||||
view.onScroll(e, e, -dpToPixels(150), 0f)
|
||||
view.onScroll(null, null, -dpToPixels(150), 0f)
|
||||
view.invalidate()
|
||||
assertRenders(view, BASE_PATH + "renderDataOffset.png")
|
||||
}
|
||||
|
||||
@@ -20,15 +20,15 @@ package org.isoron.uhabits.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
|
||||
@@ -20,6 +20,9 @@ package org.isoron.uhabits.activities.habits.list.views
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.MediumTest
|
||||
import com.nhaarman.mockitokotlin2.doReturn
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.BaseViewTest
|
||||
@@ -27,9 +30,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.HintList
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@MediumTest
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
~ You should have received a copy of the GNU General Public License along
|
||||
~ with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.isoron.uhabits">
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
|
||||
<application
|
||||
android:name=".HabitsApplication"
|
||||
@@ -30,7 +29,6 @@
|
||||
android:backupAgent=".HabitsBackupAgent"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/main_activity_title"
|
||||
android:localeConfig="@xml/locales_config"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppBaseTheme">
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Locale;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
@@ -23,13 +23,14 @@ import android.graphics.Paint.*;
|
||||
import android.os.*;
|
||||
import androidx.core.view.*;
|
||||
import androidx.core.view.accessibility.*;
|
||||
|
||||
import androidx.core.widget.*;
|
||||
import android.text.format.*;
|
||||
import android.view.*;
|
||||
import android.view.accessibility.*;
|
||||
|
||||
import androidx.customview.widget.ExploreByTouchHelper;
|
||||
|
||||
import com.android.*;
|
||||
import com.android.datetimepicker.*;
|
||||
import com.android.datetimepicker.date.MonthAdapter.*;
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.graphics.Paint.*;
|
||||
import android.util.*;
|
||||
import android.view.*;
|
||||
|
||||
import com.android.*;
|
||||
import com.android.datetimepicker.*;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
@@ -28,6 +28,7 @@ import android.view.View.*;
|
||||
import android.view.accessibility.*;
|
||||
import android.widget.*;
|
||||
|
||||
import com.android.*;
|
||||
import com.android.datetimepicker.*;
|
||||
|
||||
import org.isoron.uhabits.R;
|
||||
|
||||
@@ -44,21 +44,21 @@ class AndroidDataView(
|
||||
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 onTouchEvent(event: MotionEvent?) = detector.onTouchEvent(event)
|
||||
override fun onDown(e: MotionEvent?) = true
|
||||
override fun onShowPress(e: MotionEvent?) = Unit
|
||||
|
||||
override fun onSingleTapUp(e: MotionEvent): Boolean {
|
||||
override fun onSingleTapUp(e: MotionEvent?): Boolean {
|
||||
return handleClick(e, true)
|
||||
}
|
||||
|
||||
override fun onLongPress(e: MotionEvent) {
|
||||
override fun onLongPress(e: MotionEvent?) {
|
||||
handleClick(e)
|
||||
}
|
||||
|
||||
override fun onScroll(
|
||||
e1: MotionEvent?,
|
||||
e2: MotionEvent,
|
||||
e2: MotionEvent?,
|
||||
dx: Float,
|
||||
dy: Float
|
||||
): Boolean {
|
||||
@@ -80,7 +80,7 @@ class AndroidDataView(
|
||||
|
||||
override fun onFling(
|
||||
e1: MotionEvent?,
|
||||
e2: MotionEvent,
|
||||
e2: MotionEvent?,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
@@ -100,7 +100,7 @@ class AndroidDataView(
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onAnimationUpdate(animation: ValueAnimator) {
|
||||
override fun onAnimationUpdate(animation: ValueAnimator?) {
|
||||
if (!scroller.isFinished) {
|
||||
scroller.computeScrollOffset()
|
||||
updateDataOffset()
|
||||
@@ -127,11 +127,11 @@ class AndroidDataView(
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleClick(e: MotionEvent, isSingleTap: Boolean = false): Boolean {
|
||||
private fun handleClick(e: MotionEvent?, isSingleTap: Boolean = false): Boolean {
|
||||
val x: Float
|
||||
val y: Float
|
||||
try {
|
||||
val pointerId = e.getPointerId(0)
|
||||
val pointerId = e!!.getPointerId(0)
|
||||
x = e.getX(pointerId)
|
||||
y = e.getY(pointerId)
|
||||
} catch (ex: RuntimeException) {
|
||||
|
||||
@@ -33,19 +33,17 @@ import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
||||
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
||||
import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome
|
||||
import org.isoron.uhabits.utils.getCenter
|
||||
import org.isoron.uhabits.utils.sres
|
||||
|
||||
class CheckmarkDialog : AppCompatDialogFragment() {
|
||||
var onToggle: (Int, String, Float, Float) -> Unit = { _, _, _, _ -> }
|
||||
var onToggle: (Int, String) -> Unit = { _, _ -> }
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val appComponent = (requireActivity().application as HabitsApplication).component
|
||||
val prefs = appComponent.preferences
|
||||
val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context))
|
||||
val color = requireArguments().getInt("color")
|
||||
arrayOf(view.yesBtn, view.skipBtn).forEach {
|
||||
it.setTextColor(color)
|
||||
it.setTextColor(requireArguments().getInt("color"))
|
||||
}
|
||||
arrayOf(view.noBtn, view.unknownBtn).forEach {
|
||||
it.setTextColor(view.root.sres.getColor(R.attr.contrast60))
|
||||
@@ -64,8 +62,7 @@ class CheckmarkDialog : AppCompatDialogFragment() {
|
||||
}
|
||||
fun onClick(v: Int) {
|
||||
val notes = view.notes.text.toString().trim()
|
||||
val location = view.yesBtn.getCenter()
|
||||
onToggle(v, notes, location.x, location.y)
|
||||
onToggle(v, notes)
|
||||
requireDialog().dismiss()
|
||||
}
|
||||
view.yesBtn.setOnClickListener { onClick(YES_MANUAL) }
|
||||
|
||||
@@ -22,101 +22,97 @@ package org.isoron.uhabits.activities.common.dialogs
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.RadioButton
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import kotlinx.android.synthetic.main.frequency_picker_dialog.view.*
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.databinding.FrequencyPickerDialogBinding
|
||||
|
||||
class FrequencyPickerDialog(
|
||||
var freqNumerator: Int,
|
||||
var freqDenominator: Int
|
||||
) : AppCompatDialogFragment() {
|
||||
private var _binding: FrequencyPickerDialogBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
lateinit var contentView: View
|
||||
var onFrequencyPicked: (num: Int, den: Int) -> Unit = { _, _ -> }
|
||||
|
||||
constructor() : this(1, 1)
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
_binding = FrequencyPickerDialogBinding.inflate(LayoutInflater.from(requireActivity()))
|
||||
val inflater = LayoutInflater.from(requireActivity())
|
||||
contentView = inflater.inflate(R.layout.frequency_picker_dialog, null)
|
||||
|
||||
addBeforeAfterText(
|
||||
this.getString(R.string.every_x_days),
|
||||
binding.everyXDaysContainer
|
||||
contentView.everyXDaysContainer
|
||||
)
|
||||
|
||||
addBeforeAfterText(
|
||||
this.getString(R.string.x_times_per_week),
|
||||
binding.xTimesPerWeekContainer
|
||||
contentView.xTimesPerWeekContainer
|
||||
)
|
||||
|
||||
addBeforeAfterText(
|
||||
this.getString(R.string.x_times_per_month),
|
||||
binding.xTimesPerMonthContainer
|
||||
contentView.xTimesPerMonthContainer
|
||||
)
|
||||
|
||||
addBeforeAfterText(
|
||||
this.getString(R.string.x_times_per_y_days),
|
||||
binding.xTimesPerYDaysContainer
|
||||
contentView.xTimesPerYDaysContainer
|
||||
)
|
||||
|
||||
binding.everyDayRadioButton.setOnClickListener {
|
||||
check(binding.everyDayRadioButton)
|
||||
contentView.everyDayRadioButton.setOnClickListener {
|
||||
check(contentView.everyDayRadioButton)
|
||||
}
|
||||
|
||||
binding.everyXDaysRadioButton.setOnClickListener {
|
||||
check(binding.everyXDaysRadioButton)
|
||||
val everyXDaysTextView = binding.everyXDaysTextView
|
||||
contentView.everyXDaysRadioButton.setOnClickListener {
|
||||
check(contentView.everyXDaysRadioButton)
|
||||
val everyXDaysTextView = contentView.everyXDaysTextView
|
||||
selectInputField(everyXDaysTextView)
|
||||
}
|
||||
|
||||
binding.everyXDaysTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(binding.everyXDaysRadioButton)
|
||||
contentView.everyXDaysTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(contentView.everyXDaysRadioButton)
|
||||
}
|
||||
|
||||
binding.xTimesPerWeekRadioButton.setOnClickListener {
|
||||
check(binding.xTimesPerWeekRadioButton)
|
||||
selectInputField(binding.xTimesPerWeekTextView)
|
||||
contentView.xTimesPerWeekRadioButton.setOnClickListener {
|
||||
check(contentView.xTimesPerWeekRadioButton)
|
||||
selectInputField(contentView.xTimesPerWeekTextView)
|
||||
}
|
||||
|
||||
binding.xTimesPerWeekTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(binding.xTimesPerWeekRadioButton)
|
||||
contentView.xTimesPerWeekTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(contentView.xTimesPerWeekRadioButton)
|
||||
}
|
||||
|
||||
binding.xTimesPerMonthRadioButton.setOnClickListener {
|
||||
check(binding.xTimesPerMonthRadioButton)
|
||||
selectInputField(binding.xTimesPerMonthTextView)
|
||||
contentView.xTimesPerMonthRadioButton.setOnClickListener {
|
||||
check(contentView.xTimesPerMonthRadioButton)
|
||||
selectInputField(contentView.xTimesPerMonthTextView)
|
||||
}
|
||||
|
||||
binding.xTimesPerMonthTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(binding.xTimesPerMonthRadioButton)
|
||||
contentView.xTimesPerMonthTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(contentView.xTimesPerMonthRadioButton)
|
||||
}
|
||||
|
||||
binding.xTimesPerYDaysRadioButton.setOnClickListener {
|
||||
check(binding.xTimesPerYDaysRadioButton)
|
||||
selectInputField(binding.xTimesPerYDaysXTextView)
|
||||
contentView.xTimesPerYDaysRadioButton.setOnClickListener {
|
||||
check(contentView.xTimesPerYDaysRadioButton)
|
||||
selectInputField(contentView.xTimesPerYDaysXTextView)
|
||||
}
|
||||
|
||||
binding.xTimesPerYDaysXTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(binding.xTimesPerYDaysRadioButton)
|
||||
contentView.xTimesPerYDaysXTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(contentView.xTimesPerYDaysRadioButton)
|
||||
}
|
||||
|
||||
binding.xTimesPerYDaysYTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(binding.xTimesPerYDaysRadioButton)
|
||||
contentView.xTimesPerYDaysYTextView.setOnFocusChangeListener { v, hasFocus ->
|
||||
if (hasFocus) check(contentView.xTimesPerYDaysRadioButton)
|
||||
}
|
||||
|
||||
return AlertDialog.Builder(requireActivity())
|
||||
.setView(binding.root)
|
||||
.setView(contentView)
|
||||
.setPositiveButton(R.string.save) { _, _ -> onSaveClicked() }
|
||||
.create()
|
||||
}
|
||||
@@ -138,35 +134,31 @@ class FrequencyPickerDialog(
|
||||
var numerator = 1
|
||||
var denominator = 1
|
||||
when {
|
||||
binding.everyDayRadioButton.isChecked -> {
|
||||
contentView.everyDayRadioButton.isChecked -> {
|
||||
// NOP
|
||||
}
|
||||
|
||||
binding.everyXDaysRadioButton.isChecked -> {
|
||||
if (binding.everyXDaysTextView.text.isNotEmpty()) {
|
||||
denominator = Integer.parseInt(binding.everyXDaysTextView.text.toString())
|
||||
contentView.everyXDaysRadioButton.isChecked -> {
|
||||
if (contentView.everyXDaysTextView.text.isNotEmpty()) {
|
||||
denominator = Integer.parseInt(contentView.everyXDaysTextView.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
binding.xTimesPerWeekRadioButton.isChecked -> {
|
||||
if (binding.xTimesPerWeekTextView.text.isNotEmpty()) {
|
||||
numerator = Integer.parseInt(binding.xTimesPerWeekTextView.text.toString())
|
||||
contentView.xTimesPerWeekRadioButton.isChecked -> {
|
||||
if (contentView.xTimesPerWeekTextView.text.isNotEmpty()) {
|
||||
numerator = Integer.parseInt(contentView.xTimesPerWeekTextView.text.toString())
|
||||
denominator = 7
|
||||
}
|
||||
}
|
||||
|
||||
binding.xTimesPerYDaysRadioButton.isChecked -> {
|
||||
if (binding.xTimesPerYDaysXTextView.text.isNotEmpty() && binding.xTimesPerYDaysYTextView.text.isNotEmpty()) {
|
||||
contentView.xTimesPerYDaysRadioButton.isChecked -> {
|
||||
if (contentView.xTimesPerYDaysXTextView.text.isNotEmpty() && contentView.xTimesPerYDaysYTextView.text.isNotEmpty()) {
|
||||
numerator =
|
||||
Integer.parseInt(binding.xTimesPerYDaysXTextView.text.toString())
|
||||
Integer.parseInt(contentView.xTimesPerYDaysXTextView.text.toString())
|
||||
denominator =
|
||||
Integer.parseInt(binding.xTimesPerYDaysYTextView.text.toString())
|
||||
Integer.parseInt(contentView.xTimesPerYDaysYTextView.text.toString())
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
if (binding.xTimesPerMonthTextView.text.isNotEmpty()) {
|
||||
numerator = Integer.parseInt(binding.xTimesPerMonthTextView.text.toString())
|
||||
if (contentView.xTimesPerMonthTextView.text.isNotEmpty()) {
|
||||
numerator = Integer.parseInt(contentView.xTimesPerMonthTextView.text.toString())
|
||||
denominator = 30
|
||||
}
|
||||
}
|
||||
@@ -193,27 +185,27 @@ class FrequencyPickerDialog(
|
||||
private fun populateViews() {
|
||||
uncheckAll()
|
||||
if (freqDenominator == 30 || freqDenominator == 31) {
|
||||
binding.xTimesPerMonthRadioButton.isChecked = true
|
||||
binding.xTimesPerMonthTextView.setText(freqNumerator.toString())
|
||||
selectInputField(binding.xTimesPerMonthTextView)
|
||||
contentView.xTimesPerMonthRadioButton.isChecked = true
|
||||
contentView.xTimesPerMonthTextView.setText(freqNumerator.toString())
|
||||
selectInputField(contentView.xTimesPerMonthTextView)
|
||||
} else {
|
||||
if (freqNumerator == 1) {
|
||||
if (freqDenominator == 1) {
|
||||
binding.everyDayRadioButton.isChecked = true
|
||||
contentView.everyDayRadioButton.isChecked = true
|
||||
} else {
|
||||
binding.everyXDaysRadioButton.isChecked = true
|
||||
binding.everyXDaysTextView.setText(freqDenominator.toString())
|
||||
selectInputField(binding.everyXDaysTextView)
|
||||
contentView.everyXDaysRadioButton.isChecked = true
|
||||
contentView.everyXDaysTextView.setText(freqDenominator.toString())
|
||||
selectInputField(contentView.everyXDaysTextView)
|
||||
}
|
||||
} else {
|
||||
if (freqDenominator == 7) {
|
||||
binding.xTimesPerWeekRadioButton.isChecked = true
|
||||
binding.xTimesPerWeekTextView.setText(freqNumerator.toString())
|
||||
selectInputField(binding.xTimesPerWeekTextView)
|
||||
contentView.xTimesPerWeekRadioButton.isChecked = true
|
||||
contentView.xTimesPerWeekTextView.setText(freqNumerator.toString())
|
||||
selectInputField(contentView.xTimesPerWeekTextView)
|
||||
} else {
|
||||
binding.xTimesPerYDaysRadioButton.isChecked = true
|
||||
binding.xTimesPerYDaysXTextView.setText(freqNumerator.toString())
|
||||
binding.xTimesPerYDaysYTextView.setText(freqDenominator.toString())
|
||||
contentView.xTimesPerYDaysRadioButton.isChecked = true
|
||||
contentView.xTimesPerYDaysXTextView.setText(freqNumerator.toString())
|
||||
contentView.xTimesPerYDaysYTextView.setText(freqDenominator.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,10 +216,10 @@ class FrequencyPickerDialog(
|
||||
}
|
||||
|
||||
private fun uncheckAll() {
|
||||
binding.everyDayRadioButton.isChecked = false
|
||||
binding.everyXDaysRadioButton.isChecked = false
|
||||
binding.xTimesPerWeekRadioButton.isChecked = false
|
||||
binding.xTimesPerMonthRadioButton.isChecked = false
|
||||
binding.xTimesPerYDaysRadioButton.isChecked = false
|
||||
contentView.everyDayRadioButton.isChecked = false
|
||||
contentView.everyXDaysRadioButton.isChecked = false
|
||||
contentView.xTimesPerWeekRadioButton.isChecked = false
|
||||
contentView.xTimesPerMonthRadioButton.isChecked = false
|
||||
contentView.xTimesPerYDaysRadioButton.isChecked = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,17 @@ package org.isoron.uhabits.activities.common.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.text.method.DigitsKeyListener
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
|
||||
import org.isoron.uhabits.utils.InterfaceUtils
|
||||
import org.isoron.uhabits.utils.getCenter
|
||||
import org.isoron.uhabits.utils.requestFocusWithKeyboard
|
||||
import org.isoron.uhabits.utils.sres
|
||||
import java.text.DecimalFormat
|
||||
@@ -25,7 +22,7 @@ import java.text.ParseException
|
||||
|
||||
class NumberDialog : AppCompatDialogFragment() {
|
||||
|
||||
var onToggle: (Double, String, Float, Float) -> Unit = { _, _, _, _ -> }
|
||||
var onToggle: (Double, String) -> Unit = { _, _ -> }
|
||||
var onDismiss: () -> Unit = {}
|
||||
|
||||
private var originalNotes: String = ""
|
||||
@@ -68,7 +65,7 @@ class NumberDialog : AppCompatDialogFragment() {
|
||||
save()
|
||||
}
|
||||
view.skipBtnNumber.setOnClickListener {
|
||||
view.value.setText(DecimalFormat("#.###").format((Entry.SKIP.toDouble() / 1000)))
|
||||
view.value.setText((Entry.SKIP.toDouble() / 1000).toString())
|
||||
save()
|
||||
}
|
||||
view.notes.setOnEditorActionListener { v, actionId, event ->
|
||||
@@ -89,15 +86,6 @@ class NumberDialog : AppCompatDialogFragment() {
|
||||
// https://stackoverflow.com/a/34256139
|
||||
val separator = DecimalFormatSymbols.getInstance().decimalSeparator
|
||||
view.value.keyListener = DigitsKeyListener.getInstance("0123456789$separator")
|
||||
|
||||
// https://github.com/flutter/flutter/issues/61175
|
||||
val currKeyboard = Settings.Secure.getString(
|
||||
requireContext().contentResolver,
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD
|
||||
)
|
||||
if (currKeyboard.contains("swiftkey") || currKeyboard.contains("samsung")) {
|
||||
view.value.inputType = EditorInfo.TYPE_CLASS_TEXT
|
||||
}
|
||||
}
|
||||
|
||||
fun save() {
|
||||
@@ -105,17 +93,12 @@ class NumberDialog : AppCompatDialogFragment() {
|
||||
try {
|
||||
val numberFormat = NumberFormat.getInstance()
|
||||
val valueStr = view.value.text.toString()
|
||||
value = if (valueStr.isNotEmpty()) {
|
||||
numberFormat.parse(valueStr)!!.toDouble()
|
||||
} else {
|
||||
Entry.UNKNOWN.toDouble() / 1000
|
||||
}
|
||||
value = numberFormat.parse(valueStr)!!.toDouble()
|
||||
} catch (e: ParseException) {
|
||||
// NOP
|
||||
}
|
||||
val notes = view.notes.text.toString()
|
||||
val location = view.saveBtn.getCenter()
|
||||
onToggle(value, notes, location.x, location.y)
|
||||
onToggle(value, notes)
|
||||
requireDialog().dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,6 @@ class RingView : View {
|
||||
private var em = 0f
|
||||
private var text: String?
|
||||
private var textSize: Float
|
||||
private var isStrokedTextEnabled: Boolean = false
|
||||
private var enableFontAwesome = false
|
||||
private var internalDrawingCache: Bitmap? = null
|
||||
private var cacheCanvas: Canvas? = null
|
||||
@@ -132,10 +131,6 @@ class RingView : View {
|
||||
invalidate()
|
||||
}
|
||||
|
||||
fun setIsStrokedTextEnabled(isStroked: Boolean) {
|
||||
this.isStrokedTextEnabled = isStroked
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
super.onDraw(canvas)
|
||||
val activeCanvas: Canvas?
|
||||
@@ -164,12 +159,6 @@ class RingView : View {
|
||||
pRing!!.xfermode = null
|
||||
pRing!!.color = color
|
||||
pRing!!.textSize = textSize
|
||||
|
||||
if (isStrokedTextEnabled) {
|
||||
pRing!!.style = Paint.Style.STROKE
|
||||
pRing!!.strokeWidth = textSize / 15f
|
||||
}
|
||||
|
||||
if (enableFontAwesome) pRing!!.typeface = getFontAwesome(context)
|
||||
activeCanvas.drawText(
|
||||
text!!,
|
||||
|
||||
@@ -65,7 +65,7 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
|
||||
}
|
||||
|
||||
override fun onFling(
|
||||
e1: MotionEvent?,
|
||||
e1: MotionEvent,
|
||||
e2: MotionEvent,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
@@ -116,7 +116,7 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
|
||||
return BundleSavedState(superState, bundle)
|
||||
}
|
||||
|
||||
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, dx: Float, dy: Float): Boolean {
|
||||
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, dx: Float, dy: Float): Boolean {
|
||||
var dx = dx
|
||||
if (scrollerBucketSize == 0) return false
|
||||
if (abs(dx) > abs(dy)) {
|
||||
|
||||
@@ -35,6 +35,11 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import com.android.datetimepicker.time.RadialPickerLayout
|
||||
import com.android.datetimepicker.time.TimePickerDialog
|
||||
import kotlinx.android.synthetic.main.activity_edit_habit.nameInput
|
||||
import kotlinx.android.synthetic.main.activity_edit_habit.notesInput
|
||||
import kotlinx.android.synthetic.main.activity_edit_habit.questionInput
|
||||
import kotlinx.android.synthetic.main.activity_edit_habit.targetInput
|
||||
import kotlinx.android.synthetic.main.activity_edit_habit.unitInput
|
||||
import org.isoron.platform.gui.toInt
|
||||
import org.isoron.uhabits.HabitsApplication
|
||||
import org.isoron.uhabits.R
|
||||
@@ -266,9 +271,9 @@ class EditHabitActivity : AppCompatActivity() {
|
||||
habit.copyFrom(original)
|
||||
}
|
||||
|
||||
habit.name = binding.nameInput.text.trim().toString()
|
||||
habit.question = binding.questionInput.text.trim().toString()
|
||||
habit.description = binding.notesInput.text.trim().toString()
|
||||
habit.name = nameInput.text.trim().toString()
|
||||
habit.question = questionInput.text.trim().toString()
|
||||
habit.description = notesInput.text.trim().toString()
|
||||
habit.color = color
|
||||
if (reminderHour >= 0) {
|
||||
habit.reminder = Reminder(reminderHour, reminderMin, reminderDays)
|
||||
@@ -278,9 +283,9 @@ class EditHabitActivity : AppCompatActivity() {
|
||||
|
||||
habit.frequency = Frequency(freqNum, freqDen)
|
||||
if (habitType == HabitType.NUMERICAL) {
|
||||
habit.targetValue = binding.targetInput.text.toString().toDouble()
|
||||
habit.targetValue = targetInput.text.toString().toDouble()
|
||||
habit.targetType = targetType
|
||||
habit.unit = binding.unitInput.text.trim().toString()
|
||||
habit.unit = unitInput.text.trim().toString()
|
||||
}
|
||||
habit.type = habitType
|
||||
|
||||
@@ -303,13 +308,13 @@ class EditHabitActivity : AppCompatActivity() {
|
||||
|
||||
private fun validate(): Boolean {
|
||||
var isValid = true
|
||||
if (binding.nameInput.text.isEmpty()) {
|
||||
binding.nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
|
||||
if (nameInput.text.isEmpty()) {
|
||||
nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
|
||||
isValid = false
|
||||
}
|
||||
if (habitType == HabitType.NUMERICAL) {
|
||||
if (binding.targetInput.text.isEmpty()) {
|
||||
binding.targetInput.error = getString(R.string.validation_cannot_be_blank)
|
||||
if (targetInput.text.isEmpty()) {
|
||||
targetInput.error = getString(R.string.validation_cannot_be_blank)
|
||||
isValid = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,17 +19,12 @@
|
||||
|
||||
package org.isoron.uhabits.activities.habits.list
|
||||
|
||||
import android.Manifest.permission.POST_NOTIFICATIONS
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat.checkSelfPermission
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.isoron.uhabits.BaseExceptionHandler
|
||||
@@ -61,16 +56,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
||||
lateinit var midnightTimer: MidnightTimer
|
||||
private val scope = CoroutineScope(Dispatchers.Main)
|
||||
|
||||
private var permissionAlreadyRequested = false
|
||||
private val permissionLauncher =
|
||||
registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scheduleReminders()
|
||||
} else {
|
||||
Log.i("ListHabitsActivity", "POST_NOTIFICATIONS denied")
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var menu: ListHabitsMenu
|
||||
|
||||
override fun onQuestionMarksChanged() {
|
||||
@@ -116,26 +101,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
||||
screen.onAttached()
|
||||
rootView.postInvalidate()
|
||||
midnightTimer.onResume()
|
||||
|
||||
if (appComponent.reminderScheduler.hasHabitsWithReminders()) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
scheduleReminders()
|
||||
} else {
|
||||
if (checkSelfPermission(this, POST_NOTIFICATIONS) == PERMISSION_GRANTED) {
|
||||
scheduleReminders()
|
||||
} else {
|
||||
// If we have not requested the permission yet, request it. Otherwide do
|
||||
// nothing. This check is necessary to avoid an infinite onResume loop in case
|
||||
// the user denies the permission.
|
||||
if (!permissionAlreadyRequested) {
|
||||
Log.i("ListHabitsActivity", "Requestion permission: POST_NOTIFICATIONS")
|
||||
permissionLauncher.launch(POST_NOTIFICATIONS)
|
||||
permissionAlreadyRequested = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appComponent.reminderScheduler.scheduleAll()
|
||||
taskRunner.run {
|
||||
try {
|
||||
AutoBackup(this@ListHabitsActivity).run()
|
||||
@@ -151,10 +117,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
private fun scheduleReminders() {
|
||||
appComponent.reminderScheduler.scheduleAll()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(m: Menu): Boolean {
|
||||
menu.onCreate(menuInflater, m)
|
||||
return true
|
||||
@@ -165,7 +127,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
|
||||
return menu.onItemSelected(item)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(request: Int, result: Int, data: Intent?) {
|
||||
super.onActivityResult(request, result, data)
|
||||
screen.onResult(request, result, data)
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.Context
|
||||
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.RelativeLayout
|
||||
import nl.dionsegijn.konfetti.xml.KonfettiView
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.activities.common.views.ScrollableChart
|
||||
import org.isoron.uhabits.activities.common.views.TaskProgressBar
|
||||
@@ -70,9 +69,6 @@ class ListHabitsRootView @Inject constructor(
|
||||
val listView: HabitCardListView = habitCardListViewFactory.create()
|
||||
val llEmpty = EmptyListView(context)
|
||||
val tbar = buildToolbar()
|
||||
val konfettiView = KonfettiView(context).apply {
|
||||
translationZ = 10f
|
||||
}
|
||||
val progressBar = TaskProgressBar(context, runner)
|
||||
val hintView: HintView
|
||||
val header = HeaderView(context, preferences, midnightTimer)
|
||||
@@ -84,7 +80,6 @@ class ListHabitsRootView @Inject constructor(
|
||||
|
||||
val rootView = RelativeLayout(context).apply {
|
||||
background = sres.getDrawable(R.attr.windowBackgroundColor)
|
||||
addAtTop(konfettiView)
|
||||
addAtTop(tbar)
|
||||
addBelow(header, tbar)
|
||||
addBelow(listView, header, height = MATCH_PARENT)
|
||||
|
||||
@@ -25,9 +25,6 @@ import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.Lazy
|
||||
import nl.dionsegijn.konfetti.core.Party
|
||||
import nl.dionsegijn.konfetti.core.Position
|
||||
import nl.dionsegijn.konfetti.core.emitter.Emitter
|
||||
import org.isoron.platform.gui.toInt
|
||||
import org.isoron.uhabits.R
|
||||
import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog
|
||||
@@ -66,7 +63,6 @@ import org.isoron.uhabits.intents.IntentFactory
|
||||
import org.isoron.uhabits.tasks.ExportDBTaskFactory
|
||||
import org.isoron.uhabits.tasks.ImportDataTask
|
||||
import org.isoron.uhabits.tasks.ImportDataTaskFactory
|
||||
import org.isoron.uhabits.utils.ColorUtils
|
||||
import org.isoron.uhabits.utils.copyTo
|
||||
import org.isoron.uhabits.utils.currentTheme
|
||||
import org.isoron.uhabits.utils.dismissCurrentAndShow
|
||||
@@ -76,7 +72,6 @@ import org.isoron.uhabits.utils.showSendEmailScreen
|
||||
import org.isoron.uhabits.utils.showSendFileScreen
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
const val RESULT_IMPORT_DATA = 101
|
||||
@@ -223,28 +218,6 @@ class ListHabitsScreen
|
||||
activity.showSendFileScreen(filename)
|
||||
}
|
||||
|
||||
override fun showConfetti(color: PaletteColor, x: Float, y: Float) {
|
||||
val baseColor = themeSwitcher.currentTheme!!.color(color).toInt()
|
||||
rootView.get().konfettiView.start(
|
||||
Party(
|
||||
speed = 0f,
|
||||
maxSpeed = 16f,
|
||||
damping = 0.9f,
|
||||
spread = 360,
|
||||
angle = 0,
|
||||
colors = listOf(
|
||||
ColorUtils.changeHue(baseColor, 180f),
|
||||
ColorUtils.changeHue(baseColor, 20f),
|
||||
ColorUtils.changeHue(baseColor, -20f),
|
||||
baseColor
|
||||
),
|
||||
position = Position.Absolute(x, y),
|
||||
emitter = Emitter(duration = 25, TimeUnit.MILLISECONDS).max(25),
|
||||
timeToLive = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun showSettingsScreen() {
|
||||
val intent = intentFactory.startSettingsActivity(activity)
|
||||
activity.startActivityForResult(intent, REQUEST_SETTINGS)
|
||||
@@ -267,7 +240,7 @@ class ListHabitsScreen
|
||||
putDouble("value", value)
|
||||
putString("notes", notes)
|
||||
}
|
||||
dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) }
|
||||
dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) }
|
||||
dialog.dismissCurrentAndShow(fm, "numberDialog")
|
||||
}
|
||||
|
||||
@@ -285,7 +258,7 @@ class ListHabitsScreen
|
||||
putInt("value", selectedValue)
|
||||
putString("notes", notes)
|
||||
}
|
||||
dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) }
|
||||
dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) }
|
||||
dialog.dismissCurrentAndShow(fm, "checkmarkDialog")
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
package org.isoron.uhabits.activities.habits.list.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.PointF
|
||||
import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
@@ -155,17 +154,7 @@ class HabitCardView(
|
||||
checkmarkPanel = checkmarkPanelFactory.create().apply {
|
||||
onToggle = { timestamp, value, notes ->
|
||||
triggerRipple(timestamp)
|
||||
val location = getAbsoluteButtonLocation(timestamp)
|
||||
habit?.let {
|
||||
behavior.onToggle(
|
||||
it,
|
||||
timestamp,
|
||||
value,
|
||||
notes,
|
||||
location.x,
|
||||
location.y
|
||||
)
|
||||
}
|
||||
habit?.let { behavior.onToggle(it, timestamp, value, notes) }
|
||||
}
|
||||
onEdit = { timestamp ->
|
||||
triggerRipple(timestamp)
|
||||
@@ -217,27 +206,12 @@ class HabitCardView(
|
||||
}
|
||||
|
||||
fun triggerRipple(timestamp: Timestamp) {
|
||||
val location = getRelativeButtonLocation(timestamp)
|
||||
triggerRipple(location.x, location.y)
|
||||
}
|
||||
|
||||
private fun getRelativeButtonLocation(timestamp: Timestamp): PointF {
|
||||
val today = DateUtils.getTodayWithOffset()
|
||||
val offset = timestamp.daysUntil(today) - dataOffset
|
||||
val button = checkmarkPanel.buttons[offset]
|
||||
val y = button.height / 2.0f
|
||||
val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat()
|
||||
return PointF(x, y)
|
||||
}
|
||||
|
||||
private fun getAbsoluteButtonLocation(timestamp: Timestamp): PointF {
|
||||
val containerLocation = IntArray(2)
|
||||
this.getLocationOnScreen(containerLocation)
|
||||
val relButtonLocation = getRelativeButtonLocation(timestamp)
|
||||
return PointF(
|
||||
containerLocation[0].toFloat() + relButtonLocation.x,
|
||||
containerLocation[1].toFloat() - relButtonLocation.y
|
||||
)
|
||||
triggerRipple(x, y)
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
|
||||
@@ -179,7 +179,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
putDouble("value", value)
|
||||
putString("notes", notes)
|
||||
}
|
||||
dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) }
|
||||
dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) }
|
||||
dialog.dismissCurrentAndShow(supportFragmentManager, "numberDialog")
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
|
||||
putInt("value", selectedValue)
|
||||
putString("notes", notes)
|
||||
}
|
||||
dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) }
|
||||
dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) }
|
||||
dialog.dismissCurrentAndShow(supportFragmentManager, "checkmarkDialog")
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context,
|
||||
|
||||
fun setState(state: BarCardState) {
|
||||
val androidColor = state.theme.color(state.color).toInt()
|
||||
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.getDefault())).apply {
|
||||
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.US)).apply {
|
||||
series = mutableListOf(state.entries.map { it.value / 1000.0 })
|
||||
colors = mutableListOf(theme.color(state.color.paletteIndex))
|
||||
axis = state.entries.map { it.timestamp.toLocalDate() }
|
||||
|
||||
@@ -53,8 +53,6 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis
|
||||
private var ringtoneManager: RingtoneManager? = null
|
||||
private lateinit var prefs: Preferences
|
||||
private var widgetUpdater: WidgetUpdater? = null
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
if (requestCode == RINGTONE_REQUEST_CODE) {
|
||||
ringtoneManager!!.update(data)
|
||||
|
||||
@@ -25,7 +25,6 @@ import android.app.AlarmManager.RTC_WAKEUP
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Context.ALARM_SERVICE
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import org.isoron.uhabits.core.AppScope
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
@@ -57,10 +56,6 @@ class IntentScheduler
|
||||
)
|
||||
return SchedulerResult.IGNORED
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !manager.canScheduleExactAlarms()) {
|
||||
Log.e("IntentScheduler", "No permission to schedule exact alarms")
|
||||
return SchedulerResult.IGNORED
|
||||
}
|
||||
manager.setExactAndAllowWhileIdle(alarmType, timestamp, intent)
|
||||
return SchedulerResult.OK
|
||||
}
|
||||
|
||||
@@ -66,13 +66,7 @@ class ReminderController @Inject constructor(
|
||||
}
|
||||
|
||||
fun onDismiss(habit: Habit) {
|
||||
if (preferences.shouldMakeNotificationsSticky()) {
|
||||
// This is a workaround to keep sticky notifications non-dismissible in Android 14+.
|
||||
// If the notification is dismissed, we immediately reshow it.
|
||||
notificationTray.reshow(habit)
|
||||
} else {
|
||||
notificationTray.cancel(habit)
|
||||
}
|
||||
notificationTray.cancel(habit)
|
||||
}
|
||||
|
||||
private fun showSnoozeDelayPicker(habit: Habit, context: Context) {
|
||||
|
||||
@@ -60,14 +60,12 @@ class AndroidTaskRunner : TaskRunner {
|
||||
publishProgress(progress)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun doInBackground(vararg params: Void?): Void? {
|
||||
if (isCancelled) return null
|
||||
task.doInBackground()
|
||||
return null
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPostExecute(aVoid: Void?) {
|
||||
if (isCancelled) return
|
||||
task.onPostExecute()
|
||||
@@ -76,7 +74,6 @@ class AndroidTaskRunner : TaskRunner {
|
||||
for (l in listeners) l.onTaskFinished(task)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onPreExecute() {
|
||||
if (isCancelled) return
|
||||
for (l in listeners) l.onTaskStarted(task)
|
||||
@@ -85,7 +82,6 @@ class AndroidTaskRunner : TaskRunner {
|
||||
task.onPreExecute()
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onProgressUpdate(vararg values: Int?) {
|
||||
values[0]?.let { task.onProgressUpdate(it) }
|
||||
}
|
||||
|
||||
@@ -36,13 +36,6 @@ object ColorUtils {
|
||||
return a or r or g or b
|
||||
}
|
||||
|
||||
fun changeHue(color: Int, delta: Float): Int {
|
||||
val hsv = FloatArray(3)
|
||||
Color.colorToHSV(color, hsv)
|
||||
hsv[0] = (hsv[0] + delta).mod(360f)
|
||||
return Color.HSVToColor(hsv)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun setAlpha(color: Int, newAlpha: Float): Int {
|
||||
val intAlpha = (newAlpha * 255).toInt()
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.content.Intent
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PointF
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Handler
|
||||
import android.os.SystemClock
|
||||
@@ -136,11 +135,7 @@ fun Activity.startActivitySafely(intent: Intent) {
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.showSendEmailScreen(
|
||||
@StringRes toId: Int,
|
||||
@StringRes subjectId: Int,
|
||||
content: String?
|
||||
) {
|
||||
fun Activity.showSendEmailScreen(@StringRes toId: Int, @StringRes subjectId: Int, content: String?) {
|
||||
val to = this.getString(toId)
|
||||
val subject = this.getString(subjectId)
|
||||
this.startActivity(
|
||||
@@ -237,11 +232,3 @@ fun View.requestFocusWithKeyboard() {
|
||||
dispatchTouchEvent(MotionEvent.obtain(time, time, MotionEvent.ACTION_UP, 0f, 0f, 0))
|
||||
}, 250)
|
||||
}
|
||||
|
||||
fun View.getCenter(): PointF {
|
||||
val viewLocation = IntArray(2)
|
||||
this.getLocationOnScreen(viewLocation)
|
||||
viewLocation[0] += this.width / 2
|
||||
viewLocation[1] -= this.height / 2
|
||||
return PointF(viewLocation[0].toFloat(), viewLocation[1].toFloat())
|
||||
}
|
||||
|
||||
@@ -68,13 +68,13 @@ class CheckmarkWidgetView : HabitWidgetView {
|
||||
val fgColor: Int
|
||||
setShadowAlpha(0x4f)
|
||||
when (entryState) {
|
||||
YES_MANUAL, SKIP, YES_AUTO -> {
|
||||
YES_MANUAL, SKIP -> {
|
||||
bgColor = activeColor
|
||||
fgColor = res.getColor(R.attr.contrast0)
|
||||
backgroundPaint!!.color = bgColor
|
||||
frame!!.setBackgroundDrawable(background)
|
||||
}
|
||||
NO, UNKNOWN -> {
|
||||
YES_AUTO, NO, UNKNOWN -> {
|
||||
bgColor = res.getColor(R.attr.cardBgColor)
|
||||
fgColor = res.getColor(R.attr.contrast60)
|
||||
}
|
||||
@@ -87,23 +87,12 @@ class CheckmarkWidgetView : HabitWidgetView {
|
||||
ring.setColor(fgColor)
|
||||
ring.setBackgroundColor(bgColor)
|
||||
ring.setText(text)
|
||||
ring.setIsStrokedTextEnabled(strokedTextEnabled)
|
||||
label.text = name
|
||||
label.setTextColor(fgColor)
|
||||
requestLayout()
|
||||
postInvalidate()
|
||||
}
|
||||
|
||||
private val strokedTextEnabled: Boolean
|
||||
get() = if (isNumerical) {
|
||||
false
|
||||
} else {
|
||||
when (entryState) {
|
||||
YES_AUTO -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private val text: String
|
||||
get() = if (isNumerical) {
|
||||
(max(0, entryValue) / 1000.0).toShortString()
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:inputType="textCapSentences|textMultiLine"
|
||||
android:inputType="textCapSentences"
|
||||
android:textSize="@dimen/smallTextSize"
|
||||
android:padding="4dp"
|
||||
android:background="@color/transparent"
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/smallTextSize"
|
||||
android:maxLines="2"
|
||||
android:textColor="@color/white"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ 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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="color_background">@color/grey_900</color>
|
||||
</resources>
|
||||
@@ -89,5 +89,4 @@
|
||||
</array>
|
||||
|
||||
<color name="ic_launcher_background">#1976D2</color>
|
||||
<color name="color_background">@color/grey_200</color>
|
||||
</resources>
|
||||
@@ -61,7 +61,6 @@
|
||||
<item name="widgetShadowAlpha">0.25</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="windowBackgroundColor">@color/grey_200</item>
|
||||
<item name="android:colorBackground">@color/color_background</item>
|
||||
<item name="android:textColorAlertDialogListItem">@color/grey_800</item>
|
||||
<item name="singleLineTitle">false</item>
|
||||
<item name="dialogFormLabelColor">@color/white</item>
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<locale android:name="en" /> <!-- English -->
|
||||
<locale android:name="af-ZA" /> <!-- Afrikaans -->
|
||||
<locale android:name="ar-SA" /> <!-- Arabic -->
|
||||
<locale android:name="bg-BG" /> <!-- Bulgarian -->
|
||||
<locale android:name="ca-ES" /> <!-- Catalan -->
|
||||
<locale android:name="cs-CZ" /> <!-- Czech -->
|
||||
<locale android:name="da-DK" /> <!-- Danish -->
|
||||
<locale android:name="de-DE" /> <!-- German -->
|
||||
<locale android:name="el-GR" /> <!-- Greek -->
|
||||
<locale android:name="eo-UY" /> <!-- Esperanto -->
|
||||
<locale android:name="es-ES" /> <!-- Spanish -->
|
||||
<locale android:name="eu-ES" /> <!-- Basque -->
|
||||
<locale android:name="fa-IR" /> <!-- Farsi -->
|
||||
<locale android:name="fi-FI" /> <!-- Finnish -->
|
||||
<locale android:name="fr-FR" /> <!-- French -->
|
||||
<locale android:name="hi-IN" /> <!-- Hindi -->
|
||||
<locale android:name="hr-HR" /> <!-- Croatian -->
|
||||
<locale android:name="hu-HU" /> <!-- Hungarian -->
|
||||
<locale android:name="hy-AM" /> <!-- Armenian -->
|
||||
<locale android:name="in-ID" /> <!-- Indonesian -->
|
||||
<locale android:name="it-IT" /> <!-- Italian -->
|
||||
<locale android:name="iw-IL" /> <!-- Hebrew -->
|
||||
<locale android:name="ja-JP" /> <!-- Japanese -->
|
||||
<locale android:name="ko-KR" /> <!-- Korean -->
|
||||
<locale android:name="nl-NL" /> <!-- Dutch -->
|
||||
<locale android:name="no-NO" /> <!-- Norwegian -->
|
||||
<locale android:name="pl-PL" /> <!-- Polish -->
|
||||
<locale android:name="pt-BR" /> <!-- Portuguese (Brazil) -->
|
||||
<locale android:name="pt-PT" /> <!-- Portuguese (Portugal) -->
|
||||
<locale android:name="ro-RO" /> <!-- Romanian -->
|
||||
<locale android:name="ru-RU" /> <!-- Russian -->
|
||||
<locale android:name="sk-SK" /> <!-- Slovak -->
|
||||
<locale android:name="sl-SL" /> <!-- Slovenian -->
|
||||
<locale android:name="sr-CS" /> <!-- Serbian (Latin) -->
|
||||
<locale android:name="sr-SP" /> <!-- Serbian (Cyrillic) -->
|
||||
<locale android:name="sv-SE" /> <!-- Swedish -->
|
||||
<locale android:name="ta-IN" /> <!-- Tamil -->
|
||||
<locale android:name="te-IN" /> <!-- Telugu -->
|
||||
<locale android:name="tr-TR" /> <!-- Turkish -->
|
||||
<locale android:name="ug-CN" /> <!-- Uyghur -->
|
||||
<locale android:name="uk-UA" /> <!-- Ukrainian -->
|
||||
<locale android:name="vi-VN" /> <!-- Vietnamese -->
|
||||
<locale android:name="zh-CN" /> <!-- Chinese (Simplified) -->
|
||||
<locale android:name="zh-TW" /> <!-- Chinese (Traditional) -->
|
||||
</locale-config>
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits
|
||||
|
||||
import com.nhaarman.mockitokotlin2.spy
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.memory.MemoryModelFactory
|
||||
@@ -30,7 +31,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.junit.MockitoJUnitRunner
|
||||
import org.mockito.kotlin.spy
|
||||
|
||||
@RunWith(MockitoJUnitRunner::class)
|
||||
open class BaseAndroidJVMTest {
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.isoron.uhabits.receivers
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import org.isoron.uhabits.BaseAndroidJVMTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
@@ -25,9 +28,6 @@ import org.isoron.uhabits.core.preferences.Preferences
|
||||
import org.isoron.uhabits.core.reminders.ReminderScheduler
|
||||
import org.isoron.uhabits.core.ui.NotificationTray
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
|
||||
class ReminderControllerTest : BaseAndroidJVMTest() {
|
||||
private lateinit var controller: ReminderController
|
||||
|
||||
@@ -24,7 +24,6 @@ plugins {
|
||||
|
||||
kotlin {
|
||||
jvm().withJava()
|
||||
jvmToolchain(11)
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting {
|
||||
@@ -44,14 +43,14 @@ kotlin {
|
||||
val jvmMain by getting {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib-jdk8"))
|
||||
compileOnly("com.google.dagger:dagger:2.51.1")
|
||||
implementation("com.google.guava:guava:33.1.0-android")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3")
|
||||
implementation("androidx.annotation:annotation:1.7.1")
|
||||
compileOnly("com.google.dagger:dagger:2.46")
|
||||
implementation("com.google.guava:guava:31.1-android")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4")
|
||||
implementation("androidx.annotation:annotation:1.5.0")
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
implementation("com.opencsv:opencsv:5.9")
|
||||
implementation("commons-codec:commons-codec:1.16.0")
|
||||
implementation("org.apache.commons:commons-lang3:3.14.0")
|
||||
implementation("com.opencsv:opencsv:5.7.1")
|
||||
implementation("commons-codec:commons-codec:1.15")
|
||||
implementation("org.apache.commons:commons-lang3:3.12.0")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,11 +58,10 @@ kotlin {
|
||||
dependencies {
|
||||
implementation(kotlin("test"))
|
||||
implementation(kotlin("test-junit"))
|
||||
implementation("org.xerial:sqlite-jdbc:3.45.1.0")
|
||||
implementation("org.xerial:sqlite-jdbc:3.40.0.0")
|
||||
implementation("org.hamcrest:hamcrest:2.2")
|
||||
implementation("org.apache.commons:commons-io:1.3.2")
|
||||
implementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||
implementation("org.junit.jupiter:junit-jupiter:5.10.1")
|
||||
implementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ class JavaUserFile(val path: Path) : UserFile {
|
||||
@Suppress("NewApi")
|
||||
class JavaFileOpener : FileOpener {
|
||||
override fun openUserFile(path: String): UserFile {
|
||||
val resolvedPath = Paths.get("/tmp/$path")
|
||||
return JavaUserFile(resolvedPath)
|
||||
val path = Paths.get("/tmp/$path")
|
||||
return JavaUserFile(path)
|
||||
}
|
||||
|
||||
override fun openResourceFile(path: String): ResourceFile {
|
||||
|
||||
@@ -45,14 +45,14 @@ internal class Tokenizer(
|
||||
if (s == null || s.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
if (s[0].code != mCurrent) {
|
||||
if (s[0].toInt() != mCurrent) {
|
||||
return false
|
||||
}
|
||||
val len = s.length
|
||||
mStream.mark(len - 1)
|
||||
for (n in 1 until len) {
|
||||
val value = mStream.read()
|
||||
if (value != s[n].code) {
|
||||
if (value != s[n].toInt()) {
|
||||
mStream.reset()
|
||||
return false
|
||||
}
|
||||
@@ -68,9 +68,10 @@ object SQLParser {
|
||||
private const val STATE_COMMENT_BLOCK = 3
|
||||
|
||||
fun parse(stream: InputStream): List<String> {
|
||||
val buffer = BufferedInputStream(stream)
|
||||
val commands: MutableList<String> = ArrayList()
|
||||
val sb = StringBuffer()
|
||||
BufferedInputStream(stream).use { buffer ->
|
||||
buffer.use { buffer ->
|
||||
val tokenizer = Tokenizer(buffer)
|
||||
var state = STATE_NONE
|
||||
while (tokenizer.hasNext()) {
|
||||
|
||||
@@ -61,7 +61,7 @@ data class Habit(
|
||||
return if (isNumerical) {
|
||||
when (targetType) {
|
||||
NumericalHabitType.AT_LEAST -> value / 1000.0 >= targetValue
|
||||
NumericalHabitType.AT_MOST -> value != Entry.UNKNOWN && value / 1000.0 <= targetValue
|
||||
NumericalHabitType.AT_MOST -> value / 1000.0 <= targetValue
|
||||
}
|
||||
} else {
|
||||
value != Entry.NO && value != Entry.UNKNOWN
|
||||
|
||||
@@ -115,11 +115,6 @@ class ReminderScheduler @Inject constructor(
|
||||
for (habit in reminderHabits) schedule(habit)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun hasHabitsWithReminders(): Boolean {
|
||||
return !habitList.getFiltered(HabitMatcher.WITH_ALARM).isEmpty
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun startListening() {
|
||||
commandRunner.addListener(this)
|
||||
|
||||
@@ -25,5 +25,5 @@ fun interface Task {
|
||||
fun onAttached(runner: TaskRunner) {}
|
||||
fun onPostExecute() {}
|
||||
fun onPreExecute() {}
|
||||
fun onProgressUpdate(currentPosition: Int) {}
|
||||
fun onProgressUpdate(value: Int) {}
|
||||
}
|
||||
|
||||
@@ -89,12 +89,6 @@ class NotificationTray @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun reshow(habit: Habit) {
|
||||
active[habit]?.let {
|
||||
taskRunner.execute(ShowNotificationTask(habit, it))
|
||||
}
|
||||
}
|
||||
|
||||
interface SystemTray {
|
||||
fun removeNotification(notificationId: Int)
|
||||
fun showNotification(
|
||||
|
||||
@@ -20,12 +20,9 @@ package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
|
||||
import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.HabitList
|
||||
import org.isoron.uhabits.core.models.HabitType
|
||||
import org.isoron.uhabits.core.models.NumericalHabitType.AT_LEAST
|
||||
import org.isoron.uhabits.core.models.NumericalHabitType.AT_MOST
|
||||
import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
@@ -55,16 +52,8 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
val entry = habit.computedEntries.get(timestamp!!)
|
||||
if (habit.type == HabitType.NUMERICAL) {
|
||||
val oldValue = entry.value.toDouble() / 1000
|
||||
screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String, x: Float, y: Float ->
|
||||
screen.showNumberPopup(oldValue, entry.notes) { newValue: Double, newNotes: String ->
|
||||
val value = (newValue * 1000).roundToInt()
|
||||
if (newValue != oldValue) {
|
||||
if (
|
||||
(habit.targetType == AT_LEAST && newValue >= habit.targetValue) ||
|
||||
(habit.targetType == AT_MOST && newValue <= habit.targetValue)
|
||||
) {
|
||||
screen.showConfetti(habit.color, x, y)
|
||||
}
|
||||
}
|
||||
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes))
|
||||
}
|
||||
} else {
|
||||
@@ -72,8 +61,7 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
entry.value,
|
||||
entry.notes,
|
||||
habit.color
|
||||
) { newValue: Int, newNotes: String, x: Float, y: Float ->
|
||||
if (newValue != entry.value && newValue == YES_MANUAL) screen.showConfetti(habit.color, x, y)
|
||||
) { newValue, newNotes ->
|
||||
commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, newValue, newNotes))
|
||||
}
|
||||
}
|
||||
@@ -129,11 +117,10 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
if (prefs.isFirstRun) onFirstRun()
|
||||
}
|
||||
|
||||
fun onToggle(habit: Habit, timestamp: Timestamp, value: Int, notes: String, x: Float, y: Float) {
|
||||
fun onToggle(habit: Habit, timestamp: Timestamp, value: Int, notes: String) {
|
||||
commandRunner.run(
|
||||
CreateRepetitionCommand(habitList, habit, timestamp, value, notes)
|
||||
)
|
||||
if (value == YES_MANUAL) screen.showConfetti(habit.color, x, y)
|
||||
}
|
||||
|
||||
enum class Message {
|
||||
@@ -157,22 +144,12 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
}
|
||||
|
||||
fun interface NumberPickerCallback {
|
||||
fun onNumberPicked(
|
||||
newValue: Double,
|
||||
notes: String,
|
||||
x: Float,
|
||||
y: Float
|
||||
)
|
||||
fun onNumberPicked(newValue: Double, notes: String)
|
||||
fun onNumberPickerDismissed() {}
|
||||
}
|
||||
|
||||
fun interface CheckMarkDialogCallback {
|
||||
fun onNotesSaved(
|
||||
value: Int,
|
||||
notes: String,
|
||||
x: Float,
|
||||
y: Float
|
||||
)
|
||||
fun onNotesSaved(value: Int, notes: String)
|
||||
fun onNotesDismissed() {}
|
||||
}
|
||||
|
||||
@@ -193,6 +170,5 @@ open class ListHabitsBehavior @Inject constructor(
|
||||
)
|
||||
fun showSendBugReportToDeveloperScreen(log: String)
|
||||
fun showSendFileScreen(filename: String)
|
||||
fun showConfetti(color: PaletteColor, x: Float, y: Float)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ class HistoryCardPresenter(
|
||||
entry.value,
|
||||
entry.notes,
|
||||
habit.color
|
||||
) { newValue, newNotes, _: Float, _: Float ->
|
||||
) { newValue, newNotes ->
|
||||
commandRunner.run(
|
||||
CreateRepetitionCommand(
|
||||
habitList,
|
||||
@@ -135,7 +135,7 @@ class HistoryCardPresenter(
|
||||
screen.showNumberPopup(
|
||||
value = oldValue / 1000.0,
|
||||
notes = entry.notes
|
||||
) { newValue: Double, newNotes: String, _: Float, _: Float ->
|
||||
) { newValue: Double, newNotes: String ->
|
||||
val thousands = (newValue * 1000).roundToInt()
|
||||
commandRunner.run(
|
||||
CreateRepetitionCommand(
|
||||
|
||||
@@ -49,7 +49,7 @@ class HabitListHeader(
|
||||
|
||||
repeat(nButtons) { index ->
|
||||
val date = today.minus(nButtons - index - 1)
|
||||
val name = fmt.shortWeekdayName(date).uppercase()
|
||||
val name = fmt.shortWeekdayName(date).toUpperCase()
|
||||
val number = date.day.toString()
|
||||
|
||||
val x = width - (index + 1) * buttonSize + buttonSize / 2
|
||||
|
||||
@@ -125,30 +125,4 @@ class WidgetTheme : LightTheme() {
|
||||
override val highContrastTextColor = Color.WHITE
|
||||
override val mediumContrastTextColor = Color.WHITE.withAlpha(0.50)
|
||||
override val lowContrastTextColor = Color.WHITE.withAlpha(0.10)
|
||||
|
||||
override fun color(paletteIndex: Int): Color {
|
||||
return when (paletteIndex) {
|
||||
0 -> Color(0xD32F2F)
|
||||
1 -> Color(0xE64A19)
|
||||
2 -> Color(0xF57C00)
|
||||
3 -> Color(0xFF8F00)
|
||||
4 -> Color(0xF9A825)
|
||||
5 -> Color(0xAFB42B)
|
||||
6 -> Color(0x7CB342)
|
||||
7 -> Color(0x388E3C)
|
||||
8 -> Color(0x00897B)
|
||||
9 -> Color(0x00ACC1)
|
||||
10 -> Color(0x039BE5)
|
||||
11 -> Color(0x1976D2)
|
||||
12 -> Color(0x6275f0)
|
||||
13 -> Color(0x5E35B1)
|
||||
14 -> Color(0x8E24AA)
|
||||
15 -> Color(0xD81B60)
|
||||
16 -> Color(0x5D4037)
|
||||
17 -> Color(0x757575)
|
||||
18 -> Color(0x757575)
|
||||
19 -> Color(0x9E9E9E)
|
||||
else -> Color(0x000000)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -227,7 +227,7 @@ abstract class DateUtils {
|
||||
fun getStartOfTodayWithOffset(): Long = getStartOfDayWithOffset(getLocalTime())
|
||||
|
||||
@JvmStatic
|
||||
fun millisecondsUntilTomorrowWithOffset(): Long = getStartOfTomorrowWithOffset() - applyTimezone(getLocalTime())
|
||||
fun millisecondsUntilTomorrowWithOffset(): Long = getStartOfTomorrowWithOffset() - getLocalTime()
|
||||
|
||||
@JvmStatic
|
||||
fun getStartOfTodayCalendar(): GregorianCalendar = getCalendar(getStartOfToday())
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.isoron.uhabits.core.utils
|
||||
|
||||
import org.isoron.uhabits.core.AppScope
|
||||
import org.isoron.uhabits.core.io.Logging
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledExecutorService
|
||||
@@ -30,10 +29,9 @@ import javax.inject.Inject
|
||||
* A class that emits events when a new day starts.
|
||||
*/
|
||||
@AppScope
|
||||
open class MidnightTimer @Inject constructor(logging: Logging) {
|
||||
open class MidnightTimer @Inject constructor() {
|
||||
private val listeners: MutableList<MidnightListener> = LinkedList()
|
||||
private lateinit var executor: ScheduledExecutorService
|
||||
private val logger = logging.getLogger("MidnightTimer")
|
||||
|
||||
@Synchronized
|
||||
fun addListener(listener: MidnightListener) {
|
||||
@@ -41,10 +39,7 @@ open class MidnightTimer @Inject constructor(logging: Logging) {
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun onPause(): MutableList<Runnable>? {
|
||||
logger.info("Pausing timer")
|
||||
return executor.shutdownNow()
|
||||
}
|
||||
fun onPause(): MutableList<Runnable>? = executor.shutdownNow()
|
||||
|
||||
@Synchronized
|
||||
fun onResume(
|
||||
@@ -52,11 +47,9 @@ open class MidnightTimer @Inject constructor(logging: Logging) {
|
||||
testExecutor: ScheduledExecutorService? = null
|
||||
) {
|
||||
executor = testExecutor ?: Executors.newSingleThreadScheduledExecutor()
|
||||
val initialDelay = DateUtils.millisecondsUntilTomorrowWithOffset() + delayOffsetInMillis
|
||||
logger.info("Scheduling refresh for $initialDelay ms from now")
|
||||
executor.scheduleAtFixedRate(
|
||||
{ notifyListeners() },
|
||||
initialDelay,
|
||||
DateUtils.millisecondsUntilTomorrowWithOffset() + delayOffsetInMillis,
|
||||
DateUtils.DAY_LENGTH,
|
||||
TimeUnit.MILLISECONDS
|
||||
)
|
||||
@@ -67,7 +60,6 @@ open class MidnightTimer @Inject constructor(logging: Logging) {
|
||||
|
||||
@Synchronized
|
||||
private fun notifyListeners() {
|
||||
logger.info("Midnight refresh")
|
||||
for (l in listeners) {
|
||||
l.atMidnight()
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
|
||||
package org.isoron.platform.gui
|
||||
|
||||
import junit.framework.Assert.fail
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.isoron.platform.io.JavaFileOpener
|
||||
import org.junit.Assert.fail
|
||||
import org.junit.Test
|
||||
import java.awt.image.BufferedImage
|
||||
import java.awt.image.BufferedImage.TYPE_INT_ARGB
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core
|
||||
|
||||
import com.nhaarman.mockitokotlin2.spy
|
||||
import com.nhaarman.mockitokotlin2.validateMockitoUsage
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.isoron.uhabits.core.commands.CommandRunner
|
||||
import org.isoron.uhabits.core.database.Database
|
||||
@@ -38,8 +40,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.junit.MockitoJUnitRunner
|
||||
import org.mockito.kotlin.spy
|
||||
import org.mockito.kotlin.validateMockitoUsage
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.commands
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ArchiveHabitsCommandTest : BaseUnitTest() {
|
||||
private lateinit var command: ArchiveHabitsCommand
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.commands
|
||||
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -26,7 +27,6 @@ import org.isoron.uhabits.core.models.Reminder
|
||||
import org.isoron.uhabits.core.models.WeekdayList
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class CreateHabitCommandTest : BaseUnitTest() {
|
||||
private lateinit var command: CreateHabitCommand
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.commands
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
@@ -25,7 +26,6 @@ import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class CreateRepetitionCommandTest : BaseUnitTest() {
|
||||
private lateinit var command: CreateRepetitionCommand
|
||||
|
||||
@@ -23,13 +23,18 @@ import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
import org.junit.rules.ExpectedException
|
||||
import java.util.LinkedList
|
||||
|
||||
class DeleteHabitsCommandTest : BaseUnitTest() {
|
||||
private lateinit var command: DeleteHabitsCommand
|
||||
private lateinit var selected: LinkedList<Habit>
|
||||
|
||||
@get:Rule
|
||||
var thrown = ExpectedException.none()!!
|
||||
|
||||
@Before
|
||||
@Throws(Exception::class)
|
||||
override fun setUp() {
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.commands
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class UnarchiveHabitsCommandTest : BaseUnitTest() {
|
||||
private lateinit var command: UnarchiveHabitsCommand
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.database
|
||||
|
||||
import junit.framework.Assert.assertNull
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder
|
||||
@@ -26,7 +27,6 @@ import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class RepositoryTest : BaseUnitTest() {
|
||||
private lateinit var repository: Repository<ThingRecord>
|
||||
|
||||
@@ -27,10 +27,13 @@ import org.isoron.uhabits.core.database.Database
|
||||
import org.isoron.uhabits.core.database.MigrationHelper
|
||||
import org.isoron.uhabits.core.models.sqlite.SQLModelFactory
|
||||
import org.isoron.uhabits.core.test.HabitFixtures
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.jupiter.api.Assertions.assertThrows
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
class Version22Test : BaseUnitTest() {
|
||||
@get:Rule
|
||||
var exception = ExpectedException.none()!!
|
||||
private lateinit var db: Database
|
||||
private lateinit var helper: MigrationHelper
|
||||
|
||||
@@ -73,8 +76,8 @@ class Version22Test : BaseUnitTest() {
|
||||
@Throws(Exception::class)
|
||||
fun testDisallowNewRepsWithInvalidRef() {
|
||||
helper.migrateTo(22)
|
||||
val exception = assertThrows(java.lang.RuntimeException::class.java) { db.execute("insert into Repetitions(habit, timestamp, value) values (99999, 100, 2)") }
|
||||
assertThat(exception.message, Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
db.execute("insert into Repetitions(habit, timestamp, value) values (99999, 100, 2)")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -94,12 +97,8 @@ class Version22Test : BaseUnitTest() {
|
||||
@Throws(Exception::class)
|
||||
fun testDisallowNullTimestamp() {
|
||||
helper.migrateTo(22)
|
||||
|
||||
val exception = assertThrows(java.lang.RuntimeException::class.java) {
|
||||
db.execute("insert into Repetitions(habit, value) " + "values (0, 2)")
|
||||
}
|
||||
|
||||
assertThat(exception.message, Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
db.execute("insert into Repetitions(habit, value) " + "values (0, 2)")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -119,12 +118,8 @@ class Version22Test : BaseUnitTest() {
|
||||
@Throws(Exception::class)
|
||||
fun testDisallowNullHabit() {
|
||||
helper.migrateTo(22)
|
||||
|
||||
val exception = assertThrows(java.lang.RuntimeException::class.java) {
|
||||
db.execute("insert into Repetitions(timestamp, value) " + "values (5, 2)")
|
||||
}
|
||||
|
||||
assertThat(exception.message, Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
db.execute("insert into Repetitions(timestamp, value) " + "values (5, 2)")
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,11 +142,7 @@ class Version22Test : BaseUnitTest() {
|
||||
fun testDisallowNewDuplicateTimestamps() {
|
||||
helper.migrateTo(22)
|
||||
db.execute("insert into repetitions(habit, timestamp, value)values (0, 100, 2)")
|
||||
|
||||
val exception = assertThrows(java.lang.RuntimeException::class.java) {
|
||||
db.execute("insert into repetitions(habit, timestamp, value)values (0, 100, 5)")
|
||||
}
|
||||
|
||||
assertThat(exception.message, Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
exception.expectMessage(Matchers.containsString("SQLITE_CONSTRAINT"))
|
||||
db.execute("insert into repetitions(habit, timestamp, value)values (0, 100, 5)")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.io
|
||||
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.apache.commons.io.IOUtils
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -28,9 +29,8 @@ import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import java.util.*
|
||||
import java.util.LinkedList
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class HabitsCSVExporterTest : BaseUnitTest() {
|
||||
private lateinit var baseDir: File
|
||||
@@ -102,8 +102,9 @@ class HabitsCSVExporterTest : BaseUnitTest() {
|
||||
private fun assertAbsolutePathExists(s: String) {
|
||||
val file = File(s)
|
||||
assertTrue(
|
||||
String.format("File %s should exist", file.absolutePath)
|
||||
) { file.exists() }
|
||||
String.format("File %s should exist", file.absolutePath),
|
||||
file.exists()
|
||||
)
|
||||
}
|
||||
|
||||
private fun assertFileAndReferenceAreEqual(s: String) {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.io
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -32,8 +34,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ImportTest : BaseUnitTest() {
|
||||
@Before
|
||||
|
||||
@@ -18,19 +18,23 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertNull
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.CoreMatchers.not
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import java.io.IOException
|
||||
import java.io.StringWriter
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import java.util.ArrayList
|
||||
|
||||
class HabitListTest : BaseUnitTest() {
|
||||
@get:Rule
|
||||
var thrown = ExpectedException.none()!!
|
||||
private lateinit var habitsArray: ArrayList<Habit>
|
||||
private lateinit var activeHabits: HabitList
|
||||
private lateinit var reminderHabits: HabitList
|
||||
@@ -169,9 +173,8 @@ class HabitListTest : BaseUnitTest() {
|
||||
fun testReorder_withInvalidArguments() {
|
||||
val h1 = habitsArray[0]
|
||||
val h2 = fixtures.createEmptyHabit()
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
habitList.reorder(h1, h2)
|
||||
}
|
||||
thrown.expect(IllegalArgumentException::class.java)
|
||||
habitList.reorder(h1, h2)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -232,17 +235,15 @@ class HabitListTest : BaseUnitTest() {
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testAdd_withFilteredList() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
activeHabits.add(fixtures.createEmptyHabit())
|
||||
}
|
||||
thrown.expect(IllegalStateException::class.java)
|
||||
activeHabits.add(fixtures.createEmptyHabit())
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun testRemove_onFilteredList() {
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
activeHabits.remove(fixtures.createEmptyHabit())
|
||||
}
|
||||
thrown.expect(IllegalStateException::class.java)
|
||||
activeHabits.remove(fixtures.createEmptyHabit())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -250,9 +251,8 @@ class HabitListTest : BaseUnitTest() {
|
||||
fun testReorder_onFilteredList() {
|
||||
val h1 = fixtures.createEmptyHabit()
|
||||
val h2 = fixtures.createEmptyHabit()
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
activeHabits.reorder(h1, h2)
|
||||
}
|
||||
thrown.expect(IllegalStateException::class.java)
|
||||
activeHabits.reorder(h1, h2)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -261,8 +261,7 @@ class HabitListTest : BaseUnitTest() {
|
||||
habitList.primaryOrder = HabitList.Order.BY_SCORE_DESC
|
||||
val h1 = habitsArray[1]
|
||||
val h2 = habitsArray[2]
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
habitList.reorder(h1, h2)
|
||||
}
|
||||
thrown.expect(IllegalStateException::class.java)
|
||||
habitList.reorder(h1, h2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,21 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers.`is`
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Assert.assertNotEquals
|
||||
import org.junit.Assert.assertThat
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
import org.junit.rules.ExpectedException
|
||||
|
||||
class HabitTest : BaseUnitTest() {
|
||||
@get:Rule
|
||||
val exception = ExpectedException.none()!!
|
||||
|
||||
@Throws(Exception::class)
|
||||
override fun setUp() {
|
||||
@@ -52,7 +55,7 @@ class HabitTest : BaseUnitTest() {
|
||||
model.reminder = Reminder(8, 30, WeekdayList(1))
|
||||
val habit = modelFactory.buildHabit()
|
||||
habit.copyFrom(model)
|
||||
assertEquals(habit.isArchived, model.isArchived)
|
||||
assertTrue(habit.isArchived == model.isArchived)
|
||||
assertThat(habit.isArchived, `is`(model.isArchived))
|
||||
assertThat(habit.color, `is`(model.color))
|
||||
assertThat(habit.frequency, equalTo(model.frequency))
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.number.IsCloseTo
|
||||
import org.hamcrest.number.OrderingComparison
|
||||
@@ -27,7 +28,6 @@ import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.util.ArrayList
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
open class BaseScoreListTest : BaseUnitTest() {
|
||||
protected lateinit var habit: Habit
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.hamcrest.Matchers.greaterThan
|
||||
@@ -25,8 +27,6 @@ import org.hamcrest.Matchers.lessThan
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TimestampTest : BaseUnitTest() {
|
||||
@Test
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models
|
||||
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class WeekdayListTest : BaseUnitTest() {
|
||||
@Test
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
package org.isoron.uhabits.core.models.sqlite
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertNull
|
||||
import org.isoron.uhabits.core.BaseUnitTest.Companion.buildMemoryDatabase
|
||||
import org.isoron.uhabits.core.database.Repository
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
@@ -28,8 +30,6 @@ import org.isoron.uhabits.core.models.sqlite.records.EntryRecord
|
||||
import org.isoron.uhabits.core.utils.DateUtils
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class SQLiteEntryListTest {
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.models.sqlite
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import junit.framework.Assert.assertNull
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -31,14 +34,14 @@ import org.isoron.uhabits.core.models.Reminder
|
||||
import org.isoron.uhabits.core.models.WeekdayList
|
||||
import org.isoron.uhabits.core.models.sqlite.records.HabitRecord
|
||||
import org.isoron.uhabits.core.test.HabitFixtures
|
||||
import org.junit.Assert.assertThrows
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.junit.rules.ExpectedException
|
||||
import java.util.ArrayList
|
||||
import kotlin.test.assertNull
|
||||
|
||||
class SQLiteHabitListTest : BaseUnitTest() {
|
||||
@get:Rule
|
||||
var exception = ExpectedException.none()!!
|
||||
private lateinit var repository: Repository<HabitRecord>
|
||||
private var listener: ModelObservable.Listener = mock()
|
||||
private lateinit var habitsArray: ArrayList<Habit>
|
||||
@@ -87,9 +90,8 @@ class SQLiteHabitListTest : BaseUnitTest() {
|
||||
val habit = modelFactory.buildHabit()
|
||||
habitList.add(habit)
|
||||
verify(listener).onModelChange()
|
||||
assertThrows(IllegalArgumentException::class.java) {
|
||||
habitList.add(habit)
|
||||
}
|
||||
exception.expect(IllegalArgumentException::class.java)
|
||||
habitList.add(habit)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.preferences
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertNull
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -26,11 +30,7 @@ import org.isoron.uhabits.core.models.Timestamp.Companion.ZERO
|
||||
import org.isoron.uhabits.core.ui.ThemeSwitcher
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import java.io.File
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class PreferencesTest : BaseUnitTest() {
|
||||
private lateinit var prefs: Preferences
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.preferences
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -25,9 +28,6 @@ import org.junit.Before
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.util.Arrays
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class PropertiesStorageTest : BaseUnitTest() {
|
||||
private lateinit var storage: PropertiesStorage
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.reminders
|
||||
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.isoron.uhabits.core.models.Reminder
|
||||
@@ -33,10 +37,6 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.anyLong
|
||||
import org.mockito.junit.MockitoJUnitRunner
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import java.util.Calendar
|
||||
import java.util.TimeZone
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.tasks
|
||||
|
||||
import com.nhaarman.mockitokotlin2.inOrder
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.JUnit4
|
||||
import org.mockito.kotlin.inOrder
|
||||
import org.mockito.kotlin.mock
|
||||
|
||||
@RunWith(JUnit4::class)
|
||||
class SingleThreadTaskRunnerTest : BaseUnitTest() {
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.reset
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -26,10 +30,6 @@ import org.isoron.uhabits.core.commands.DeleteHabitsCommand
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.reset
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
|
||||
class HabitCardListCacheTest : BaseUnitTest() {
|
||||
private lateinit var cache: HabitCardListCache
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertNull
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -25,12 +31,6 @@ import org.isoron.uhabits.core.models.Timestamp
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class HintListTest : BaseUnitTest() {
|
||||
private lateinit var hintList: HintList
|
||||
|
||||
@@ -18,6 +18,16 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import com.nhaarman.mockitokotlin2.KArgumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.clearInvocations
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
@@ -29,18 +39,8 @@ import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.KArgumentCaptor
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.clearInvocations
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ListHabitsBehaviorTest : BaseUnitTest() {
|
||||
private val dirFinder: ListHabitsBehavior.DirFinder = mock()
|
||||
@@ -84,7 +84,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() {
|
||||
eq(""),
|
||||
picker.capture()
|
||||
)
|
||||
picker.lastValue.onNumberPicked(100.0, "", 0f, 0f)
|
||||
picker.lastValue.onNumberPicked(100.0, "")
|
||||
val today = getTodayWithOffset()
|
||||
assertThat(habit2.computedEntries.get(today).value, equalTo(100000))
|
||||
}
|
||||
@@ -168,9 +168,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() {
|
||||
habit = habit1,
|
||||
timestamp = getToday(),
|
||||
value = Entry.NO,
|
||||
notes = "",
|
||||
x = 0f,
|
||||
y = 0f
|
||||
notes = ""
|
||||
)
|
||||
assertFalse(habit1.isCompletedToday())
|
||||
}
|
||||
|
||||
@@ -18,6 +18,17 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import com.nhaarman.mockitokotlin2.KArgumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.any
|
||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.clearInvocations
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.never
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -26,17 +37,6 @@ import org.isoron.uhabits.core.models.HabitMatcher
|
||||
import org.isoron.uhabits.core.preferences.Preferences
|
||||
import org.isoron.uhabits.core.ui.ThemeSwitcher
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.KArgumentCaptor
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.clearInvocations
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ListHabitsMenuBehaviorTest : BaseUnitTest() {
|
||||
private lateinit var behavior: ListHabitsMenuBehavior
|
||||
|
||||
@@ -18,6 +18,15 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.list
|
||||
|
||||
import com.nhaarman.mockitokotlin2.KArgumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.argumentCaptor
|
||||
import com.nhaarman.mockitokotlin2.eq
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertNull
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.Matchers.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -26,15 +35,6 @@ import org.isoron.uhabits.core.models.PaletteColor
|
||||
import org.isoron.uhabits.core.ui.callbacks.OnColorPickedCallback
|
||||
import org.isoron.uhabits.core.ui.callbacks.OnConfirmedCallback
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.KArgumentCaptor
|
||||
import org.mockito.kotlin.argumentCaptor
|
||||
import org.mockito.kotlin.eq
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertNull
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class ListHabitsSelectionMenuBehaviorTest : BaseUnitTest() {
|
||||
private val screen: ListHabitsSelectionMenuBehavior.Screen = mock()
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.screens.habits.show
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.apache.commons.io.FileUtils
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.models.Habit
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import java.nio.file.Files
|
||||
|
||||
class ShowHabitMenuPresenterTest : BaseUnitTest() {
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
package org.isoron.uhabits.core.ui.views
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.reset
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.isoron.platform.gui.assertRenders
|
||||
import org.isoron.platform.time.DayOfWeek
|
||||
@@ -31,10 +35,6 @@ import org.isoron.uhabits.core.ui.views.HistoryChart.Square.HATCHED
|
||||
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.OFF
|
||||
import org.isoron.uhabits.core.ui.views.HistoryChart.Square.ON
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.reset
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import java.util.Locale
|
||||
|
||||
class HistoryChartTest {
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.ui.widgets
|
||||
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import com.nhaarman.mockitokotlin2.reset
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.verifyZeroInteractions
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.commands.CreateRepetitionCommand
|
||||
import org.isoron.uhabits.core.models.Entry
|
||||
@@ -29,11 +34,6 @@ import org.isoron.uhabits.core.ui.NotificationTray
|
||||
import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.reset
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
|
||||
class WidgetBehaviorTest : BaseUnitTest() {
|
||||
private lateinit var notificationTray: NotificationTray
|
||||
@@ -61,7 +61,7 @@ class WidgetBehaviorTest : BaseUnitTest() {
|
||||
CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL, "")
|
||||
)
|
||||
verify(notificationTray).cancel(habit)
|
||||
verifyNoInteractions(preferences)
|
||||
verifyZeroInteractions(preferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -71,7 +71,7 @@ class WidgetBehaviorTest : BaseUnitTest() {
|
||||
CreateRepetitionCommand(habitList, habit, today, Entry.NO, "")
|
||||
)
|
||||
verify(notificationTray).cancel(habit)
|
||||
verifyNoInteractions(preferences)
|
||||
verifyZeroInteractions(preferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,7 +113,7 @@ class WidgetBehaviorTest : BaseUnitTest() {
|
||||
CreateRepetitionCommand(habitList, habit, today, 600, "")
|
||||
)
|
||||
verify(notificationTray).cancel(habit)
|
||||
verifyNoInteractions(preferences)
|
||||
verifyZeroInteractions(preferences)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -126,6 +126,6 @@ class WidgetBehaviorTest : BaseUnitTest() {
|
||||
CreateRepetitionCommand(habitList, habit, today, 400, "")
|
||||
)
|
||||
verify(notificationTray).cancel(habit)
|
||||
verifyNoInteractions(preferences)
|
||||
verifyZeroInteractions(preferences)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.isoron.uhabits.core.utils
|
||||
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.hamcrest.MatcherAssert.assertThat
|
||||
import org.hamcrest.core.IsEqual.equalTo
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
@@ -39,7 +40,6 @@ import java.util.Calendar
|
||||
import java.util.GregorianCalendar
|
||||
import java.util.Locale
|
||||
import java.util.TimeZone
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class DateUtilsTest : BaseUnitTest() {
|
||||
var firstWeekday = Calendar.SUNDAY
|
||||
|
||||
@@ -4,7 +4,6 @@ import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.isoron.uhabits.core.BaseUnitTest
|
||||
import org.isoron.uhabits.core.io.StandardLogging
|
||||
import org.junit.Test
|
||||
import java.util.Calendar
|
||||
import java.util.TimeZone
|
||||
@@ -35,7 +34,7 @@ class MidnightTimerTest : BaseUnitTest() {
|
||||
)
|
||||
|
||||
val suspendedListener = suspendCoroutine<Boolean> { continuation ->
|
||||
MidnightTimer(StandardLogging()).apply {
|
||||
MidnightTimer().apply {
|
||||
addListener { continuation.resume(true) }
|
||||
// When
|
||||
onResume(1, executor)
|
||||
|
||||
@@ -22,11 +22,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
plugins {
|
||||
application
|
||||
id("kotlin")
|
||||
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +34,11 @@ application {
|
||||
|
||||
dependencies {
|
||||
val ktorVersion = "1.6.8"
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.22")
|
||||
val kotlinVersion = "1.7.21"
|
||||
val logbackVersion = "1.4.5"
|
||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
|
||||
implementation("io.ktor:ktor-server-netty:$ktorVersion")
|
||||
implementation("ch.qos.logback:logback-classic:1.4.14")
|
||||
implementation("ch.qos.logback:logback-classic:$logbackVersion")
|
||||
implementation("io.ktor:ktor-server-core:$ktorVersion")
|
||||
implementation("io.ktor:ktor-html-builder:$ktorVersion")
|
||||
implementation("io.ktor:ktor-jackson:$ktorVersion")
|
||||
@@ -49,7 +47,7 @@ dependencies {
|
||||
implementation("io.prometheus:simpleclient_httpserver:0.16.0")
|
||||
implementation("io.prometheus:simpleclient_hotspot:0.16.0")
|
||||
testImplementation("io.ktor:ktor-server-tests:$ktorVersion")
|
||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
|
||||
testImplementation(kotlin("test"))
|
||||
testImplementation(kotlin("test-junit"))
|
||||
}
|
||||
@@ -59,4 +57,3 @@ tasks.withType<ShadowJar> {
|
||||
archiveClassifier.set("")
|
||||
archiveVersion.set("")
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits.sync.app
|
||||
|
||||
import org.mockito.kotlin.mock
|
||||
import com.nhaarman.mockitokotlin2.mock
|
||||
import io.ktor.application.*
|
||||
import org.isoron.uhabits.sync.server.*
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits.sync.app
|
||||
|
||||
import org.mockito.kotlin.whenever
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.isoron.uhabits.sync.app
|
||||
|
||||
import org.mockito.kotlin.whenever
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.server.testing.handleRequest
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
|
||||
package org.isoron.uhabits.sync.app
|
||||
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.whenever
|
||||
import com.nhaarman.mockitokotlin2.verify
|
||||
import com.nhaarman.mockitokotlin2.whenever
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.testing.*
|
||||
import kotlinx.coroutines.*
|
||||
|
||||
Reference in New Issue
Block a user