diff --git a/.github/dependabot.yml b/.github/dependabot.yml index dfa800a18..f770db0a4 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -4,3 +4,7 @@ updates: directory: "/" schedule: interval: "monthly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b42512d32..88be81258 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,9 +9,10 @@ on: jobs: Test: runs-on: self-hosted + timeout-minutes: 30 steps: - name: Check out source code - uses: actions/checkout@v1 + uses: actions/checkout@v3 - name: Build project run: ./build.sh build @@ -21,7 +22,7 @@ jobs: - name: Upload artifacts if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: build path: | diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9651df2..bbc344341 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## [2.1.2] -- 2023-05-26 +### Fixed +- Fix bug that caused widget to enter checkmark on wrong date (@iSoron, #1541) +- Fix widget corners on Android 12 (@iSoron) +- Fix bug that caused notes to be lost when editing a checkmark (@iSoron, #1566) +- Prevent soft keyboard from covering entry popup (@iSoron) +- Accept comma (instead of dot) in certain locales (@iSoron) + +### Changed +- Remove update delay after entering a checkmark (@iSoron) + +### Removed +- Remove stack widgets (@iSoron) + + ## [2.1.1] -- 2022-09-24 ### Fixed - Fix Tasker plugin (@iSoron, #1503) diff --git a/README.md b/README.md index 19e411c3a..9ebbb7380 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ show you how your habits improved over time. It is completely ad-free and open source.

- Get it on Google Play - Get it on F-Droid + Get it on Google Play + Get it on F-Droid

## Screenshots diff --git a/build.gradle.kts b/build.gradle.kts index 8bf47ca61..25e353b53 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,11 +1,11 @@ plugins { val kotlinVersion = "1.7.21" - id("com.android.application") version ("7.3.0-rc01") apply (false) + 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.0.0" + id("org.jlleitschuh.gradle.ktlint") version "11.4.2" } apply { diff --git a/build.sh b/build.sh index 271a2ba61..ac81802e1 100755 --- a/build.sh +++ b/build.sh @@ -217,20 +217,28 @@ android_test_parallel() { ( LOG=build/android-test-$API.log log_info "API $API: Running tests..." - if android_test $API 1>$LOG 2>&1; then + android_test $API 1>$LOG 2>&1 + ret_code=$? + if [ $ret_code = 0 ]; then log_info "API $API: Passed" else log_error "API $API: Failed" fi pkill -9 -f ${AVD_PREFIX}${API} + exit $ret_code )& PIDS+=" $!" done # Check exit codes - RET_CODE=0 + success=0 for pid in $PIDS; do - wait $pid || RET_CODE=1 + wait $pid + ret_code=$? + if [ $ret_code != 0 ]; then + success=1 + fi + echo pid=$pid ret_code=$ret_code success=$success done # Print all logs @@ -240,7 +248,7 @@ android_test_parallel() { echo "::endgroup::" done - return $RET_CODE + return $success } android_build() { diff --git a/uhabits-android/build.gradle.kts b/uhabits-android/build.gradle.kts index 4c9ba6348..d8e3f4060 100644 --- a/uhabits-android/build.gradle.kts +++ b/uhabits-android/build.gradle.kts @@ -19,7 +19,7 @@ plugins { id("com.github.triplet.play") version "3.7.0" - id("com.android.application") + id("com.android.application") version "7.4.2" id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.kapt") id("org.jetbrains.kotlin.android.extensions") @@ -35,8 +35,8 @@ android { compileSdk = 32 defaultConfig { - versionCode = 20101 - versionName = "2.1.1" + versionCode = 20200 + versionName = "2.2.0" minSdk = 28 targetSdk = 31 applicationId = "org.isoron.uhabits" @@ -80,11 +80,11 @@ android { } dependencies { - val daggerVersion = "2.43.2" + val daggerVersion = "2.46" val kotlinVersion = "1.7.21" val kxCoroutinesVersion = "1.6.4" val ktorVersion = "1.6.8" - val espressoVersion = "3.4.0" + val espressoVersion = "3.5.1" androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion") androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion") @@ -92,11 +92,11 @@ 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.4.0") - androidTestImplementation("androidx.test.ext:junit:1.1.3") + 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.4.0") - androidTestImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") + androidTestImplementation("androidx.test:rules:1.5.0") + androidTestImplementation("org.mockito.kotlin:mockito-kotlin:2.2.11") compileOnly("javax.annotation:jsr250-api:1.0") coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.2.2") implementation("com.github.AppIntro:AppIntro:6.2.0") @@ -113,14 +113,14 @@ dependencies { 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.6.1") + 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("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0") + testImplementation("org.mockito.kotlin:mockito-kotlin:2.2.11") } kapt { diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png index 642264b62..2ffbb10ac 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png index f5a3df56e..a8bf398a3 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/checked.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png index ea1aab565..bc7e34f20 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png and b/uhabits-android/src/androidTest/assets/views/widgets/CheckmarkWidgetView/large_size.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png index 3fb786226..e72c6bedf 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/FrequencyWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png index 5b71e7300..23e3c979e 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/HistoryWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png index 35f65f59e..4f50ce820 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/ScoreWidget/render.png differ diff --git a/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png b/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png index 4a8fa7f9f..5b3270649 100644 Binary files a/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png and b/uhabits-android/src/androidTest/assets/views/widgets/TargetWidget/render.png differ diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.kt index 657eaf086..5553c234a 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseUserInterfaceTest.kt @@ -39,6 +39,7 @@ open class BaseUserInterfaceTest { private lateinit var prefs: Preferences private lateinit var fixtures: HabitFixtures private lateinit var cache: HabitCardListCache + @Before @Throws(Exception::class) fun setUp() { diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseViewTest.kt index bcec69dfa..2f6daca23 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/BaseViewTest.kt @@ -153,18 +153,22 @@ open class BaseViewTest : BaseAndroidTest() { var filename = filename var dir = getSDCardDir("test-screenshots") if (dir == null) dir = AndroidDirFinder(targetContext).getFilesDir("test-screenshots") - if (dir == null) throw RuntimeException( - "Could not find suitable dir for screenshots" - ) + if (dir == null) { + throw RuntimeException( + "Could not find suitable dir for screenshots" + ) + } filename = filename.replace("\\.png$".toRegex(), "$suffix.png") val absolutePath = String.format("%s/%s", dir.absolutePath, filename) val parent = File(absolutePath).parentFile - if (!parent.exists() && !parent.mkdirs()) throw RuntimeException( - String.format( - "Could not create dir: %s", - parent.absolutePath + if (!parent.exists() && !parent.mkdirs()) { + throw RuntimeException( + String.format( + "Could not create dir: %s", + parent.absolutePath + ) ) - ) + } val out = FileOutputStream(absolutePath) bitmap.compress(Bitmap.CompressFormat.PNG, 100, out) return absolutePath diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt index a7a1b2759..38df23db2 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/HabitsActivityTestComponent.kt @@ -19,7 +19,6 @@ package org.isoron.uhabits -import com.nhaarman.mockitokotlin2.mock import dagger.Component import dagger.Module import dagger.Provides @@ -35,6 +34,7 @@ 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 { diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.kt index 3d71853ec..4f504d8be 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/ScoreChartTest.kt @@ -44,7 +44,7 @@ class ScoreChartTest : BaseViewTest() { habit = habit, firstWeekday = prefs.firstWeekdayInt, spinnerPosition = 0, - theme = LightTheme(), + theme = LightTheme() ) view = ScoreChart(targetContext).apply { setScores(state.scores) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/StreakChartTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/StreakChartTest.kt index 58ed5e7d3..ec11b27ed 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/StreakChartTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/common/views/StreakChartTest.kt @@ -30,6 +30,7 @@ import org.junit.runner.RunWith @MediumTest class StreakChartTest : BaseViewTest() { private lateinit var view: StreakChart + @Before override fun setUp() { super.setUp() diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt index f37cc1838..32df08758 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryButtonViewTest.kt @@ -44,7 +44,7 @@ class EntryButtonViewTest : BaseViewTest() { view = component.getEntryButtonViewFactory().create().apply { value = Entry.NO color = PaletteUtils.getAndroidTestColor(5) - onToggle = { _, _, _ -> toggled = true } + onToggle = { _, _ -> toggled = true } onEdit = { edited = true } } measureView(view, dpToPixels(48), dpToPixels(48)) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt index f09c48dba..de955deb8 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/EntryPanelViewTest.kt @@ -77,7 +77,7 @@ class EntryPanelViewTest : BaseViewTest() { @Test fun testToggle() { val timestamps = mutableListOf() - view.onToggle = { t, _, _, _ -> timestamps.add(t) } + view.onToggle = { t, _, _ -> timestamps.add(t) } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() @@ -88,7 +88,7 @@ class EntryPanelViewTest : BaseViewTest() { fun testToggle_withOffset() { val timestamps = mutableListOf() view.dataOffset = 3 - view.onToggle = { t, _, _, _ -> timestamps += t } + view.onToggle = { t, _, _ -> timestamps += t } view.buttons[0].performLongClick() view.buttons[2].performLongClick() view.buttons[3].performLongClick() diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HeaderViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HeaderViewTest.kt index 6bf7e2a81..3a972a57c 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HeaderViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HeaderViewTest.kt @@ -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 diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HintViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HintViewTest.kt index af1f30df8..f065d8c37 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HintViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/HintViewTest.kt @@ -20,9 +20,6 @@ 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 @@ -30,6 +27,9 @@ 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 diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt index c26b55775..66cc0a7d9 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/FrequencyCardViewTest.kt @@ -48,7 +48,7 @@ class FrequencyCardViewTest : BaseViewTest() { FrequencyCardPresenter.buildState( habit = habit, firstWeekday = 0, - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 600f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt index 71fe4e751..249f56972 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardViewTest.kt @@ -49,7 +49,7 @@ class HistoryCardViewTest : BaseViewTest() { HistoryCardPresenter.buildState( habit = habit, firstWeekday = SUNDAY, - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 600f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt index 9a5fc81d3..1018978f2 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/OverviewCardViewTest.kt @@ -51,7 +51,7 @@ class OverviewCardViewTest : BaseViewTest() { scoreYearDiff = 0.74f, totalCount = 44, color = PaletteColor(7), - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 300f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt index 8bd2bc520..85f66add2 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/ScoreCardViewTest.kt @@ -49,7 +49,7 @@ class ScoreCardViewTest : BaseViewTest() { habit = habit, firstWeekday = 0, spinnerPosition = 0, - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 600f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt index 2c70e3b92..14d5c3d27 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/StreakCardViewTest.kt @@ -48,7 +48,7 @@ class StreakCardViewTest : BaseViewTest() { StreakCardState( bestStreaks = habit.streaks.getBest(10), color = habit.color, - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 600f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt index 3323f78df..642517827 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardViewTest.kt @@ -53,7 +53,7 @@ class SubtitleCardViewTest : BaseViewTest() { isNumerical = false, question = "Did you meditate this morning?", reminder = Reminder(8, 30, EVERY_DAY), - theme = LightTheme(), + theme = LightTheme() ) ) measureView(view, 800f, 200f) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/regression/ListHabitsRegressionTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/regression/ListHabitsRegressionTest.kt index 551c76c17..d514fdbfb 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/regression/ListHabitsRegressionTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/regression/ListHabitsRegressionTest.kt @@ -119,7 +119,7 @@ class ListHabitsRegressionTest : BaseUserInterfaceTest() { "Wake up early", "Meditate", "Read books", - "Track time", + "Track time" ) } } diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.kt index f3a842f04..628a2ebbf 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.kt @@ -33,9 +33,11 @@ import java.io.IOException @MediumTest class CheckmarkWidgetViewTest : BaseViewTest() { private lateinit var view: CheckmarkWidgetView + @Before override fun setUp() { super.setUp() + similarityCutoff = 0.00025 setTheme(R.style.WidgetTheme) val habit = fixtures.createShortHabit() val computedEntries = habit.computedEntries diff --git a/uhabits-android/src/main/AndroidManifest.xml b/uhabits-android/src/main/AndroidManifest.xml index e1809301c..9377e42c0 100644 --- a/uhabits-android/src/main/AndroidManifest.xml +++ b/uhabits-android/src/main/AndroidManifest.xml @@ -19,7 +19,6 @@ - diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt index ae1d1f52f..36d79596e 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidCanvas.kt @@ -60,7 +60,7 @@ class AndroidCanvas : Canvas { y1.toDp(), x2.toDp(), y2.toDp(), - paint, + paint ) } @@ -69,7 +69,7 @@ class AndroidCanvas : Canvas { text, x.toDp(), y.toDp() + 0.6f * mHeight, - textPaint, + textPaint ) } @@ -83,7 +83,7 @@ class AndroidCanvas : Canvas { y: Double, width: Double, height: Double, - cornerRadius: Double, + cornerRadius: Double ) { paint.style = Paint.Style.FILL innerCanvas.drawRoundRect( @@ -93,7 +93,7 @@ class AndroidCanvas : Canvas { (y + height).toDp(), cornerRadius.toDp(), cornerRadius.toDp(), - paint, + paint ) } @@ -108,7 +108,7 @@ class AndroidCanvas : Canvas { y.toDp(), (x + width).toDp(), (y + height).toDp(), - paint, + paint ) } @@ -148,7 +148,7 @@ class AndroidCanvas : Canvas { centerY: Double, radius: Double, startAngle: Double, - swipeAngle: Double, + swipeAngle: Double ) { paint.style = Paint.Style.FILL innerCanvas.drawArc( @@ -159,14 +159,14 @@ class AndroidCanvas : Canvas { -startAngle.toFloat(), -swipeAngle.toFloat(), true, - paint, + paint ) } override fun fillCircle( centerX: Double, centerY: Double, - radius: Double, + radius: Double ) { paint.style = Paint.Style.FILL innerCanvas.drawCircle(centerX.toDp(), centerY.toDp(), radius.toDp(), paint) diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt index 0a8c5ee68..990314a06 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt @@ -33,7 +33,7 @@ import kotlin.math.max */ class AndroidDataView( context: Context, - attrs: AttributeSet? = null, + attrs: AttributeSet? = null ) : AndroidView(context, attrs), GestureDetector.OnGestureListener, ValueAnimator.AnimatorUpdateListener { @@ -60,7 +60,7 @@ class AndroidDataView( e1: MotionEvent?, e2: MotionEvent?, dx: Float, - dy: Float, + dy: Float ): Boolean { if (abs(dx) > abs(dy)) { val parent = parent @@ -82,7 +82,7 @@ class AndroidDataView( e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, - velocityY: Float, + velocityY: Float ): Boolean { scroller.fling( scroller.currX, @@ -140,8 +140,11 @@ class AndroidDataView( // e.getPointerId. return false } - if (isSingleTap) view?.onClick(x / canvas.innerDensity, y / canvas.innerDensity) - else view?.onLongClick(x / canvas.innerDensity, y / canvas.innerDensity) + if (isSingleTap) { + view?.onClick(x / canvas.innerDensity, y / canvas.innerDensity) + } else { + view?.onLongClick(x / canvas.innerDensity, y / canvas.innerDensity) + } return true } } diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt index 0b313f9a4..b382c220c 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidImage.kt @@ -47,6 +47,6 @@ fun Color.toInt(): Int { (255 * this.alpha).roundToInt(), (255 * this.red).roundToInt(), (255 * this.green).roundToInt(), - (255 * this.blue).roundToInt(), + (255 * this.blue).roundToInt() ) } diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt index 4fd22541c..139989178 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidView.kt @@ -24,7 +24,7 @@ import android.util.AttributeSet open class AndroidView( context: Context, - attrs: AttributeSet? = null, + attrs: AttributeSet? = null ) : android.view.View(context, attrs) { var view: T? = null diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt index be9d0eb02..c47eb968d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/AndroidThemeSwitcher.kt @@ -39,7 +39,7 @@ import org.isoron.uhabits.inject.ActivityScope class AndroidThemeSwitcher constructor( @ActivityContext val context: Context, - preferences: Preferences, + preferences: Preferences ) : ThemeSwitcher(preferences) { override var currentTheme: Theme = LightTheme() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutScreen.kt index 8909431b2..04fa715fd 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutScreen.kt @@ -27,7 +27,7 @@ import org.isoron.uhabits.utils.startActivitySafely class AboutScreen( private val activity: AboutActivity, private val intents: IntentFactory, - private val prefs: Preferences, + private val prefs: Preferences ) { private var developerCountdown = 5 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutView.kt index 5eeb67f19..bc52f6fc0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/about/AboutView.kt @@ -32,7 +32,7 @@ import org.isoron.uhabits.utils.setupToolbar @SuppressLint("ViewConstructor") class AboutView( context: Context, - private val screen: AboutScreen, + private val screen: AboutScreen ) : FrameLayout(context) { private var binding = AboutBinding.inflate(LayoutInflater.from(context)) @@ -43,7 +43,7 @@ class AboutView( toolbar = binding.toolbar, color = PaletteColor(11), title = resources.getString(R.string.about), - theme = currentTheme(), + theme = currentTheme() ) val version = resources.getString(R.string.version_n) binding.tvContributors.setOnClickListener { screen.showCodeContributorsWebsite() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt similarity index 54% rename from uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt rename to uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt index fb7f43d51..5df8ffd7b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkPopup.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -20,109 +20,60 @@ package org.isoron.uhabits.activities.common.dialogs import android.app.Dialog -import android.content.Context +import android.os.Bundle import android.view.LayoutInflater -import android.view.View import android.view.View.GONE import android.view.View.VISIBLE +import androidx.appcompat.app.AppCompatDialogFragment +import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Entry.Companion.NO import org.isoron.uhabits.core.models.Entry.Companion.SKIP import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN -import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL -import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.databinding.CheckmarkPopupBinding import org.isoron.uhabits.utils.InterfaceUtils.getFontAwesome -import org.isoron.uhabits.utils.dimBehind -import org.isoron.uhabits.utils.dismissCurrentAndShow -import org.isoron.uhabits.utils.dp import org.isoron.uhabits.utils.sres -const val POPUP_WIDTH = 4 * 48f + 16f -const val POPUP_HEIGHT = 48f * 2.5f + 8f - -class CheckmarkPopup( - private val context: Context, - private val color: Int, - private var notes: String, - private var value: Int, - private val prefs: Preferences, - private val anchor: View, -) { +class CheckmarkDialog : AppCompatDialogFragment() { var onToggle: (Int, String) -> Unit = { _, _ -> } - private lateinit var dialog: Dialog - - private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { - // Required for round corners - container.clipToOutline = true - } - init { - view.booleanButtons.visibility = VISIBLE - initColors() - initTypefaces() - hideDisabledButtons() - populate() - } - - private fun initColors() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val appComponent = (requireActivity().application as HabitsApplication).component + val prefs = appComponent.preferences + val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)) 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)) } - } - - private fun initTypefaces() { arrayOf(view.yesBtn, view.noBtn, view.skipBtn, view.unknownBtn).forEach { - it.typeface = getFontAwesome(context) + it.typeface = getFontAwesome(requireContext()) } - } - - private fun hideDisabledButtons() { + view.notes.setText(requireArguments().getString("notes")!!) if (!prefs.isSkipEnabled) view.skipBtn.visibility = GONE if (!prefs.areQuestionMarksEnabled) view.unknownBtn.visibility = GONE - } - - private fun populate() { - val selectedBtn = when (value) { - YES_MANUAL -> view.yesBtn - YES_AUTO -> view.noBtn - NO -> view.noBtn - UNKNOWN -> if (prefs.areQuestionMarksEnabled) view.unknownBtn else view.noBtn - SKIP -> if (prefs.isSkipEnabled) view.skipBtn else view.noBtn - else -> null - } - view.notes.setText(notes) - } - - fun show() { - dialog = Dialog(context, android.R.style.Theme_NoTitleBar) + view.booleanButtons.visibility = VISIBLE + val dialog = Dialog(requireContext()) dialog.setContentView(view.root) dialog.window?.apply { - setLayout( - view.root.dp(POPUP_WIDTH).toInt(), - view.root.dp(POPUP_HEIGHT).toInt() - ) setBackgroundDrawableResource(android.R.color.transparent) } fun onClick(v: Int) { - this.value = v - save() + val notes = view.notes.text.toString().trim() + onToggle(v, notes) + requireDialog().dismiss() } view.yesBtn.setOnClickListener { onClick(YES_MANUAL) } view.noBtn.setOnClickListener { onClick(NO) } view.skipBtn.setOnClickListener { onClick(SKIP) } view.unknownBtn.setOnClickListener { onClick(UNKNOWN) } - dialog.setCanceledOnTouchOutside(true) - dialog.dimBehind() - dialog.dismissCurrentAndShow() - } + view.notes.setOnEditorActionListener { v, actionId, event -> + onClick(requireArguments().getInt("value")) + true + } - fun save() { - onToggle(value, view.notes.text.toString().trim()) - dialog.dismiss() + return dialog } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt index 5173aa6f9..6c1a941eb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/FrequencyPickerDialog.kt @@ -48,22 +48,22 @@ class FrequencyPickerDialog( addBeforeAfterText( this.getString(R.string.every_x_days), - contentView.everyXDaysContainer, + contentView.everyXDaysContainer ) addBeforeAfterText( this.getString(R.string.x_times_per_week), - contentView.xTimesPerWeekContainer, + contentView.xTimesPerWeekContainer ) addBeforeAfterText( this.getString(R.string.x_times_per_month), - contentView.xTimesPerMonthContainer, + contentView.xTimesPerMonthContainer ) addBeforeAfterText( this.getString(R.string.x_times_per_y_days), - contentView.xTimesPerYDaysContainer, + contentView.xTimesPerYDaysContainer ) contentView.everyDayRadioButton.setOnClickListener { @@ -124,7 +124,8 @@ class FrequencyPickerDialog( val parts = str.split("%d") for (i in parts.indices) { container.addView( - TextView(activity).apply { text = parts[i].trim() }, 2 * i + 1, + TextView(activity).apply { text = parts[i].trim() }, + 2 * i + 1 ) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt index 27898e87f..02796eca4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt @@ -69,7 +69,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { theme = themeSwitcher.currentTheme, today = DateUtils.getTodayWithOffset().toLocalDate(), onDateClickedListener = onDateClickedListener ?: object : OnDateClickedListener {}, - padding = 10.0, + padding = 10.0 ) dataView = AndroidDataView(requireContext(), null) dataView.view = chart!! diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt new file mode 100644 index 000000000..7e10baa51 --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberDialog.kt @@ -0,0 +1,104 @@ +package org.isoron.uhabits.activities.common.dialogs + +import android.app.Dialog +import android.os.Bundle +import android.text.method.DigitsKeyListener +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.MotionEvent +import android.view.View +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.requestFocusWithKeyboard +import org.isoron.uhabits.utils.sres +import java.text.DecimalFormat +import java.text.DecimalFormatSymbols +import java.text.NumberFormat +import java.text.ParseException + +class NumberDialog : AppCompatDialogFragment() { + + var onToggle: (Double, String) -> Unit = { _, _ -> } + var onDismiss: () -> Unit = {} + + private var originalNotes: String = "" + private var originalValue: Double = 0.0 + private lateinit var view: CheckmarkPopupBinding + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val appComponent = (requireActivity().application as HabitsApplication).component + val prefs = appComponent.preferences + view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)) + arrayOf(view.yesBtn, view.skipBtn).forEach { + it.setTextColor(requireArguments().getInt("color")) + } + arrayOf(view.noBtn, view.unknownBtn).forEach { + it.setTextColor(view.root.sres.getColor(R.attr.contrast60)) + } + arrayOf(view.yesBtn, view.noBtn, view.skipBtn, view.unknownBtn).forEach { + it.typeface = InterfaceUtils.getFontAwesome(requireContext()) + } + if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = View.GONE + view.numberButtons.visibility = View.VISIBLE + fixDecimalSeparator(view) + originalNotes = requireArguments().getString("notes")!! + originalValue = requireArguments().getDouble("value") + view.notes.setText(originalNotes) + view.value.setText( + when { + originalValue < 0.01 -> "0" + else -> DecimalFormat("#.##").format(originalValue) + } + ) + view.value.setOnKeyListener { _, keyCode, event -> + if (event.action == MotionEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) { + save() + return@setOnKeyListener true + } + return@setOnKeyListener false + } + view.saveBtn.setOnClickListener { + save() + } + view.skipBtnNumber.setOnClickListener { + view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) + save() + } + view.notes.setOnEditorActionListener { v, actionId, event -> + save() + true + } + view.value.requestFocusWithKeyboard() + val dialog = Dialog(requireContext()) + dialog.setContentView(view.root) + dialog.window?.apply { + setBackgroundDrawableResource(android.R.color.transparent) + } + dialog.setOnDismissListener { onDismiss() } + return dialog + } + + private fun fixDecimalSeparator(view: CheckmarkPopupBinding) { + // https://stackoverflow.com/a/34256139 + val separator = DecimalFormatSymbols.getInstance().decimalSeparator + view.value.keyListener = DigitsKeyListener.getInstance("0123456789$separator") + } + + fun save() { + var value = originalValue + try { + val numberFormat = NumberFormat.getInstance() + val valueStr = view.value.text.toString() + value = numberFormat.parse(valueStr)!!.toDouble() + } catch (e: ParseException) { + // NOP + } + val notes = view.notes.text.toString() + onToggle(value, notes) + requireDialog().dismiss() + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt deleted file mode 100644 index c3a464311..000000000 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPopup.kt +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2016-2021 Álinson Santos Xavier - * - * This file is part of Loop Habit Tracker. - * - * Loop Habit Tracker is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation, either version 3 of the License, or (at your - * option) any later version. - * - * Loop Habit Tracker is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -package org.isoron.uhabits.activities.common.dialogs - -import android.app.Dialog -import android.content.Context -import android.view.KeyEvent.KEYCODE_ENTER -import android.view.LayoutInflater -import android.view.MotionEvent.ACTION_DOWN -import android.view.View -import android.view.View.GONE -import android.view.View.VISIBLE -import org.isoron.uhabits.core.models.Entry -import org.isoron.uhabits.core.preferences.Preferences -import org.isoron.uhabits.databinding.CheckmarkPopupBinding -import org.isoron.uhabits.utils.dimBehind -import org.isoron.uhabits.utils.dismissCurrentAndShow -import org.isoron.uhabits.utils.dp -import org.isoron.uhabits.utils.requestFocusWithKeyboard -import java.text.DecimalFormat - -class NumberPopup( - private val context: Context, - private var notes: String, - private var value: Double, - private val prefs: Preferences, - private val anchor: View, -) { - var onToggle: (Double, String) -> Unit = { _, _ -> } - var onDismiss: () -> Unit = {} - private val originalValue = value - private lateinit var dialog: Dialog - - private val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context)).apply { - // Required for round corners - container.clipToOutline = true - } - - init { - view.numberButtons.visibility = VISIBLE - hideDisabledButtons() - populate() - } - - private fun hideDisabledButtons() { - if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = GONE - } - - private fun populate() { - view.notes.setText(notes) - view.value.setText( - when { - value < 0.01 -> "0" - else -> DecimalFormat("#.##").format(value) - } - ) - } - - fun show() { - dialog = Dialog(context, android.R.style.Theme_NoTitleBar) - dialog.setContentView(view.root) - dialog.window?.apply { - setLayout( - view.root.dp(POPUP_WIDTH).toInt(), - view.root.dp(POPUP_HEIGHT).toInt() - ) - setBackgroundDrawableResource(android.R.color.transparent) - } - dialog.setOnDismissListener { - onDismiss() - } - - view.value.setOnKeyListener { _, keyCode, event -> - if (event.action == ACTION_DOWN && keyCode == KEYCODE_ENTER) { - save() - return@setOnKeyListener true - } - return@setOnKeyListener false - } - view.saveBtn.setOnClickListener { - save() - } - view.skipBtnNumber.setOnClickListener { - view.value.setText((Entry.SKIP.toDouble() / 1000).toString()) - save() - } - view.value.requestFocusWithKeyboard() - dialog.setCanceledOnTouchOutside(true) - dialog.dimBehind() - dialog.dismissCurrentAndShow() - } - - fun save() { - val value = view.value.text.toString().toDoubleOrNull() ?: originalValue - val notes = view.notes.text.toString() - onToggle(value, notes) - dialog.dismiss() - } -} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.kt index 41c67ff27..10aeaf29b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/FrequencyChart.kt @@ -181,8 +181,9 @@ class FrequencyChart : ScrollableChart { rect[0f, 0f, baseSize.toFloat()] = baseSize.toFloat() rect.offset(prevRect!!.left, prevRect!!.top + baseSize * j) val i = localeWeekdayList[j] % 7 - if (values != null) + if (values != null) { drawMarker(canvas, rect, values[i], weekDaysInMonth[i]) + } rect.offset(0f, rowHeight) } drawFooter(canvas, rect, date) @@ -196,12 +197,14 @@ class FrequencyChart : ScrollableChart { rect.centerY() - 0.1f * em, pText!! ) - if (date[Calendar.MONTH] == 1) canvas.drawText( - dfYear!!.format(time), - rect.centerX(), - rect.centerY() + 0.9f * em, - pText!! - ) + if (date[Calendar.MONTH] == 1) { + canvas.drawText( + dfYear!!.format(time), + rect.centerX(), + rect.centerY() + 0.9f * em, + pText!! + ) + } } private fun drawGrid(canvas: Canvas, rGrid: RectF?) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/RingView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/RingView.kt index 4a3b10679..870097800 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/RingView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/views/RingView.kt @@ -148,8 +148,12 @@ class RingView : View { pRing!!.color = inactiveColor!! activeCanvas.drawArc(rect!!, angle - 90, 360 - angle, true, pRing!!) if (thickness > 0) { - if (isTransparencyEnabled) pRing!!.xfermode = XFERMODE_CLEAR else pRing!!.color = - backgroundColor!! + if (isTransparencyEnabled) { + pRing!!.xfermode = XFERMODE_CLEAR + } else { + pRing!!.color = + backgroundColor!! + } rect!!.inset(thickness, thickness) activeCanvas.drawArc(rect!!, 0f, 360f, true, pRing!!) pRing!!.xfermode = null diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt index e14bdefd5..b7ca3235f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsActivity.kt @@ -40,6 +40,7 @@ import org.isoron.uhabits.inject.ActivityContextModule import org.isoron.uhabits.inject.DaggerHabitsActivityComponent import org.isoron.uhabits.inject.HabitsActivityComponent import org.isoron.uhabits.inject.HabitsApplicationComponent +import org.isoron.uhabits.utils.dismissCurrentDialog import org.isoron.uhabits.utils.restartWithFade class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { @@ -91,6 +92,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { midnightTimer.onPause() screen.onDetached() adapter.cancelRefresh() + dismissCurrentDialog() super.onPause() } @@ -99,6 +101,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener { screen.onAttached() rootView.postInvalidate() midnightTimer.onResume() + appComponent.reminderScheduler.scheduleAll() taskRunner.run { try { AutoBackup(this@ListHabitsActivity).run() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt index faa13173a..62fe3f00c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsRootView.kt @@ -94,7 +94,7 @@ class ListHabitsRootView @Inject constructor( title = resources.getString(R.string.main_activity_title), color = PaletteColor(17), displayHomeAsUpEnabled = false, - theme = currentTheme(), + theme = currentTheme() ) addView(rootView, MATCH_PARENT, MATCH_PARENT) listAdapter.setListView(listView) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index 731342974..c525e624a 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -22,14 +22,15 @@ package org.isoron.uhabits.activities.habits.list import android.app.Activity import android.content.Context import android.content.Intent +import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import dagger.Lazy import org.isoron.platform.gui.toInt import org.isoron.uhabits.R -import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup +import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog -import org.isoron.uhabits.activities.common.dialogs.NumberPopup +import org.isoron.uhabits.activities.common.dialogs.NumberDialog import org.isoron.uhabits.activities.habits.edit.HabitTypeDialog import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter import org.isoron.uhabits.core.commands.ArchiveHabitsCommand @@ -95,7 +96,7 @@ class ListHabitsScreen private val colorPickerFactory: ColorPickerDialogFactory, private val behavior: Lazy, private val preferences: Preferences, - private val rootView: Lazy, + private val rootView: Lazy ) : CommandRunner.Listener, ListHabitsBehavior.Screen, ListHabitsMenuBehavior.Screen, @@ -233,17 +234,14 @@ class ListHabitsScreen notes: String, callback: ListHabitsBehavior.NumberPickerCallback ) { - val view = rootView.get() - NumberPopup( - context = context, - prefs = preferences, - anchor = view, - notes = notes, - value = value, - ).apply { - onToggle = { value, notes -> callback.onNumberPicked(value, notes) } - show() + val fm = (context as AppCompatActivity).supportFragmentManager + val dialog = NumberDialog() + dialog.arguments = Bundle().apply { + putDouble("value", value) + putString("notes", notes) } + dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } + dialog.dismissCurrentAndShow(fm, "numberDialog") } override fun showCheckmarkPopup( @@ -252,18 +250,16 @@ class ListHabitsScreen color: PaletteColor, callback: ListHabitsBehavior.CheckMarkDialogCallback ) { - val view = rootView.get() - CheckmarkPopup( - context = context, - prefs = preferences, - anchor = view, - color = view.currentTheme().color(color).toInt(), - notes = notes, - value = selectedValue, - ).apply { - onToggle = { value, notes -> callback.onNotesSaved(value, notes) } - show() + val theme = rootView.get().currentTheme() + val fm = (context as AppCompatActivity).supportFragmentManager + val dialog = CheckmarkDialog() + dialog.arguments = Bundle().apply { + putInt("color", theme.color(color).toInt()) + putInt("value", selectedValue) + putString("notes", notes) } + dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } + dialog.dismissCurrentAndShow(fm, "checkmarkDialog") } private fun getExecuteString(command: Command): String? { @@ -325,8 +321,11 @@ class ListHabitsScreen private fun onExportDB() { taskRunner.execute( exportDBFactory.create { filename -> - if (filename != null) activity.showSendFileScreen(filename) - else activity.showMessage(activity.resources.getString(R.string.could_not_export)) + if (filename != null) { + activity.showSendFileScreen(filename) + } else { + activity.showMessage(activity.resources.getString(R.string.could_not_export)) + } } ) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/ButtonPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/ButtonPanelView.kt index faf53b298..3218ea754 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/ButtonPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/ButtonPanelView.kt @@ -60,8 +60,11 @@ abstract class ButtonPanelView( repeat(buttonCount) { buttons.add(createButton()) } removeAllViews() - if (reverse) buttons.reversed().forEach { addView(it) } - else buttons.forEach { addView(it) } + if (reverse) { + buttons.reversed().forEach { addView(it) } + } else { + buttons.forEach { addView(it) } + } setupButtons() requestLayout() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt index 176cec62a..3cf77789e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt @@ -44,8 +44,6 @@ import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.toMeasureSpec import javax.inject.Inject -const val TOGGLE_DELAY_MILLIS = 2000L - class CheckmarkButtonViewFactory @Inject constructor( @ActivityContext val context: Context, @@ -79,7 +77,7 @@ class CheckmarkButtonView( invalidate() } - var onToggle: (Int, String, Long) -> Unit = { _, _, _ -> } + var onToggle: (Int, String) -> Unit = { _, _ -> } var onEdit: () -> Unit = { } @@ -90,25 +88,31 @@ class CheckmarkButtonView( setOnLongClickListener(this) } - fun performToggle(delay: Long) { + fun performToggle() { value = Entry.nextToggleValue( value = value, isSkipEnabled = preferences.isSkipEnabled, areQuestionMarksEnabled = preferences.areQuestionMarksEnabled ) - onToggle(value, notes, delay) + onToggle(value, notes) performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) invalidate() } override fun onClick(v: View) { - if (preferences.isShortToggleEnabled) performToggle(TOGGLE_DELAY_MILLIS) - else onEdit() + if (preferences.isShortToggleEnabled) { + performToggle() + } else { + onEdit() + } } override fun onLongClick(v: View): Boolean { - if (preferences.isShortToggleEnabled) onEdit() - else performToggle(TOGGLE_DELAY_MILLIS) + if (preferences.isShortToggleEnabled) { + onEdit() + } else { + performToggle() + } return true } @@ -142,8 +146,11 @@ class CheckmarkButtonView( paint.color = when (value) { YES_MANUAL, YES_AUTO, SKIP -> color NO -> { - if (preferences.areQuestionMarksEnabled) mediumContrastColor - else lowContrastColor + if (preferences.areQuestionMarksEnabled) { + mediumContrastColor + } else { + lowContrastColor + } } else -> lowContrastColor } @@ -151,8 +158,11 @@ class CheckmarkButtonView( SKIP -> R.string.fa_skipped NO -> R.string.fa_times UNKNOWN -> { - if (preferences.areQuestionMarksEnabled) R.string.fa_question - else R.string.fa_times + if (preferences.areQuestionMarksEnabled) { + R.string.fa_question + } else { + R.string.fa_times + } } else -> R.string.fa_check } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt index 35f639691..525dac5ad 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt @@ -60,7 +60,7 @@ class CheckmarkPanelView( setupButtons() } - var onToggle: (Timestamp, Int, String, Long) -> Unit = { _, _, _, _ -> } + var onToggle: (Timestamp, Int, String) -> Unit = { _, _, _ -> } set(value) { field = value setupButtons() @@ -89,7 +89,7 @@ class CheckmarkPanelView( else -> "" } button.color = color - button.onToggle = { value, notes, delay -> onToggle(timestamp, value, notes, delay) } + button.onToggle = { value, notes -> onToggle(timestamp, value, notes) } button.onEdit = { onEdit(timestamp) } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt index 1cb3462f9..a70805139 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListController.kt @@ -156,10 +156,11 @@ class HabitCardListController @Inject constructor( } private fun notifyListener() { - if (activeMode is SelectionMode) + if (activeMode is SelectionMode) { selectionMenu.get().onSelectionChange() - else + } else { selectionMenu.get().onSelectionFinish() + } } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index 424aae50b..8e5e9d21e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -57,13 +57,6 @@ class HabitCardViewFactory fun create() = HabitCardView(context, checkmarkPanelFactory, numberPanelFactory, behavior) } -data class DelayedToggle( - var habit: Habit, - var timestamp: Timestamp, - var value: Int, - var notes: String -) - class HabitCardView( @ActivityContext context: Context, checkmarkPanelFactory: CheckmarkPanelViewFactory, @@ -136,7 +129,6 @@ class HabitCardView( private var scoreRing: RingView private var currentToggleTaskId = 0 - private var queuedToggles = mutableListOf() init { scoreRing = RingView(context).apply { @@ -160,12 +152,9 @@ class HabitCardView( } checkmarkPanel = checkmarkPanelFactory.create().apply { - onToggle = { timestamp, value, notes, delay -> - if (delay > 0) triggerRipple(timestamp) - habit?.let { - val taskId = queueToggle(it, timestamp, value, notes); - { runPendingToggles(taskId) }.delay(delay) - } + onToggle = { timestamp, value, notes -> + triggerRipple(timestamp) + habit?.let { behavior.onToggle(it, timestamp, value, notes) } } onEdit = { timestamp -> triggerRipple(timestamp) @@ -205,25 +194,6 @@ class HabitCardView( addView(innerFrame) } - @Synchronized - private fun runPendingToggles(id: Int) { - if (currentToggleTaskId != id) return - for ((h, t, v, n) in queuedToggles) behavior.onToggle(h, t, v, n) - queuedToggles.clear() - } - - @Synchronized - private fun queueToggle( - it: Habit, - timestamp: Timestamp, - value: Int, - notes: String, - ): Int { - currentToggleTaskId += 1 - queuedToggles.add(DelayedToggle(it, timestamp, value, notes)) - return currentToggleTaskId - } - override fun onModelChange() { Handler(Looper.getMainLooper()).post { habit?.let { copyAttributesFrom(it) } @@ -255,7 +225,6 @@ class HabitCardView( } private fun copyAttributesFrom(h: Habit) { - fun getActiveColor(habit: Habit): Int { return when (habit.isArchived) { true -> sres.getColor(R.attr.contrast60) @@ -301,7 +270,6 @@ class HabitCardView( } private fun updateBackground(isSelected: Boolean) { - val background = when (isSelected) { true -> R.drawable.selected_box false -> R.drawable.ripple diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.kt index fa81c1c59..c11c1bbba 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HeaderView.kt @@ -124,15 +124,20 @@ class HeaderView( rect.set(0f, 0f, width, height) rect.offset(canvas.width.toFloat() - dp(3.0f), 0f) - if (isReversed) rect.offset(-(index + 1) * width, 0f) - else rect.offset((index - buttonCount) * width, 0f) - - if (isRTL()) rect.set( - canvas.width - rect.right, - rect.top, - canvas.width - rect.left, - rect.bottom - ) + if (isReversed) { + rect.offset(-(index + 1) * width, 0f) + } else { + rect.offset((index - buttonCount) * width, 0f) + } + + if (isRTL()) { + rect.set( + canvas.width - rect.right, + rect.top, + canvas.width - rect.left, + rect.bottom + ) + } val y1 = rect.centerY() - 0.25 * em val y2 = rect.centerY() + 1.25 * em diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 3ecca1494..21289a0bd 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -34,10 +34,10 @@ import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.activities.HabitsDirFinder -import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup +import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog -import org.isoron.uhabits.activities.common.dialogs.NumberPopup +import org.isoron.uhabits.activities.common.dialogs.NumberDialog import org.isoron.uhabits.core.commands.Command import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.models.Habit @@ -51,6 +51,7 @@ import org.isoron.uhabits.core.ui.views.OnDateClickedListener import org.isoron.uhabits.intents.IntentFactory import org.isoron.uhabits.utils.currentTheme import org.isoron.uhabits.utils.dismissCurrentAndShow +import org.isoron.uhabits.utils.dismissCurrentDialog import org.isoron.uhabits.utils.showMessage import org.isoron.uhabits.utils.showSendFileScreen import org.isoron.uhabits.widgets.WidgetUpdater @@ -87,7 +88,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { habit = habit, habitList = habitList, preferences = preferences, - screen = screen, + screen = screen ) view = ShowHabitView(this) @@ -98,13 +99,13 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { habitList = habitList, screen = screen, system = HabitsDirFinder(AndroidDirFinder(this)), - taskRunner = appComponent.taskRunner, + taskRunner = appComponent.taskRunner ) menu = ShowHabitMenu( activity = this, presenter = menuPresenter, - preferences = preferences, + preferences = preferences ) view.setListener(presenter) @@ -129,6 +130,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { } override fun onPause() { + dismissCurrentDialog() commandRunner.removeListener(this) super.onPause() } @@ -148,7 +150,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { ShowHabitPresenter.buildState( habit = habit, preferences = preferences, - theme = themeSwitcher.currentTheme, + theme = themeSwitcher.currentTheme ) ) } @@ -170,41 +172,32 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { override fun showNumberPopup( value: Double, notes: String, - preferences: Preferences, callback: ListHabitsBehavior.NumberPickerCallback ) { - val anchor = getPopupAnchor() ?: return - NumberPopup( - context = this@ShowHabitActivity, - prefs = preferences, - notes = notes, - anchor = anchor, - value = value, - ).apply { - onToggle = { v, n -> callback.onNumberPicked(v, n) } - show() + val dialog = NumberDialog() + dialog.arguments = Bundle().apply { + putDouble("value", value) + putString("notes", notes) } + dialog.onToggle = { v, n -> callback.onNumberPicked(v, n) } + dialog.dismissCurrentAndShow(supportFragmentManager, "numberDialog") } override fun showCheckmarkPopup( selectedValue: Int, notes: String, - preferences: Preferences, color: PaletteColor, callback: ListHabitsBehavior.CheckMarkDialogCallback ) { - val anchor = getPopupAnchor() ?: return - CheckmarkPopup( - context = this@ShowHabitActivity, - prefs = preferences, - notes = notes, - color = view.currentTheme().color(color).toInt(), - anchor = anchor, - value = selectedValue, - ).apply { - onToggle = { v, n -> callback.onNotesSaved(v, n) } - show() + val theme = view.currentTheme() + val dialog = CheckmarkDialog() + dialog.arguments = Bundle().apply { + putInt("color", theme.color(color).toInt()) + putInt("value", selectedValue) + putString("notes", notes) } + dialog.onToggle = { v, n -> callback.onNotesSaved(v, n) } + dialog.dismissCurrentAndShow(supportFragmentManager, "checkmarkDialog") } private fun getPopupAnchor(): View? { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt index 5a4214610..60b079738 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitMenu.kt @@ -28,7 +28,7 @@ import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuPresenter class ShowHabitMenu( val activity: ShowHabitActivity, val presenter: ShowHabitMenuPresenter, - val preferences: Preferences, + val preferences: Preferences ) { fun onCreateOptionsMenu(menu: Menu): Boolean { activity.menuInflater.inflate(R.menu.show_habit, menu) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt index 38fba3baf..cbb85825e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitView.kt @@ -39,7 +39,7 @@ class ShowHabitView(context: Context) : FrameLayout(context) { binding.toolbar, title = data.title, color = data.color, - theme = data.theme, + theme = data.theme ) binding.subtitleCard.setState(data.subtitle) binding.overviewCard.setState(data.overview) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt index fa3122ed3..980f6c1d1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/BarCardView.kt @@ -63,7 +63,7 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, parent: AdapterView<*>?, view: View?, position: Int, - id: Long, + id: Long ) { presenter.onBoolSpinnerPosition(position) } @@ -77,7 +77,7 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context, parent: AdapterView<*>?, view: View?, position: Int, - id: Long, + id: Long ) { presenter.onNumericalSpinnerPosition(position) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt index 74e566fbb..f576a115a 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt @@ -45,7 +45,7 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont series = state.series, defaultSquare = state.defaultSquare, notesIndicators = state.notesIndicators, - firstWeekday = state.firstWeekday, + firstWeekday = state.firstWeekday ) binding.chart.postInvalidate() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt index 5bbfb46d6..c29894c18 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/SubtitleCardView.kt @@ -52,7 +52,7 @@ class SubtitleCardView(context: Context, attrs: AttributeSet) : LinearLayout(con binding.frequencyLabel.text = formatFrequency( state.frequency.numerator, state.frequency.denominator, - resources, + resources ) binding.questionLabel.setTextColor(color) binding.questionLabel.text = state.question diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.kt index 60a12ac17..0d5e25224 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsActivity.kt @@ -40,7 +40,7 @@ class SettingsActivity : AppCompatActivity() { toolbar = binding.toolbar, title = resources.getString(R.string.settings), color = PaletteColor(11), - theme = themeSwitcher.currentTheme, + theme = themeSwitcher.currentTheme ) setContentView(binding.root) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt index 28fbd63d8..e67f6a567 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/settings/SettingsFragment.kt @@ -22,6 +22,7 @@ import android.app.backup.BackupManager import android.content.Intent import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener +import android.net.Uri import android.os.Bundle import android.provider.Settings import android.util.Log @@ -43,6 +44,7 @@ import org.isoron.uhabits.core.utils.DateUtils.Companion.getLongWeekdayNames import org.isoron.uhabits.notifications.AndroidNotificationTray.Companion.createAndroidNotificationChannel import org.isoron.uhabits.notifications.RingtoneManager import org.isoron.uhabits.utils.StyledResources +import org.isoron.uhabits.utils.startActivitySafely import org.isoron.uhabits.widgets.WidgetUpdater import java.util.Calendar @@ -92,16 +94,24 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis override fun onPreferenceTreeClick(preference: Preference): Boolean { val key = preference.key ?: return false - if (key == "reminderSound") { - showRingtonePicker() - return true - } else if (key == "reminderCustomize") { - createAndroidNotificationChannel(requireContext()) - val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) - intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName) - intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID) - startActivity(intent) - return true + when (key) { + "reminderSound" -> { + showRingtonePicker() + return true + } + "reminderCustomize" -> { + createAndroidNotificationChannel(requireContext()) + val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) + intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName) + intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID) + startActivity(intent) + return true + } + "rateApp" -> { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.playStoreURL))) + activity?.startActivitySafely(intent) + return true + } } return super.onPreferenceTreeClick(preference) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.kt index 6361397ef..55468cfda 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingActivity.kt @@ -32,7 +32,7 @@ class EditSettingActivity : AppCompatActivity() { val habits = app.component.habitList.getFiltered( HabitMatcher( isArchivedAllowed = false, - isCompletedAllowed = true, + isCompletedAllowed = true ) ) AndroidThemeSwitcher(this, app.component.preferences).apply() @@ -43,7 +43,7 @@ class EditSettingActivity : AppCompatActivity() { context = this, habitList = app.component.habitList, onSave = controller::onSave, - args = args, + args = args ) setContentView(view) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.kt index 30c13c95d..91aaccce9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/automation/EditSettingRootView.kt @@ -54,7 +54,7 @@ class EditSettingRootView( title = resources.getString(R.string.app_name), color = PaletteColor(11), displayHomeAsUpEnabled = false, - theme = currentTheme(), + theme = currentTheme() ) populateHabitSpinner() binding.habitSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { @@ -69,7 +69,7 @@ class EditSettingRootView( val habit = habitList.getByPosition(binding.habitSpinner.selectedItemPosition) val action = mapSpinnerPositionToAction( isNumerical = habit.isNumerical, - itemPosition = binding.actionSpinner.selectedItemPosition, + itemPosition = binding.actionSpinner.selectedItemPosition ) onSave(habit, action) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt index cb0b9f894..ed2ee19a7 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.kt @@ -27,22 +27,34 @@ class AndroidCursor(private val cursor: android.database.Cursor) : Cursor { override fun moveToNext() = cursor.moveToNext() override fun getInt(index: Int): Int? { - return if (cursor.isNull(index)) null - else cursor.getInt(index) + return if (cursor.isNull(index)) { + null + } else { + cursor.getInt(index) + } } override fun getLong(index: Int): Long? { - return if (cursor.isNull(index)) null - else cursor.getLong(index) + return if (cursor.isNull(index)) { + null + } else { + cursor.getLong(index) + } } override fun getDouble(index: Int): Double? { - return if (cursor.isNull(index)) null - else cursor.getDouble(index) + return if (cursor.isNull(index)) { + null + } else { + cursor.getDouble(index) + } } override fun getString(index: Int): String? { - return if (cursor.isNull(index)) null - else cursor.getString(index) + return if (cursor.isNull(index)) { + null + } else { + cursor.getString(index) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt index d764e7a63..3c8214d7a 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.kt @@ -26,7 +26,7 @@ import java.io.File class AndroidDatabase( private val db: SQLiteDatabase, - override val file: File?, + override val file: File? ) : Database { override fun beginTransaction() = db.beginTransaction() @@ -45,7 +45,7 @@ class AndroidDatabase( tableName: String, values: Map, where: String, - vararg params: String, + vararg params: String ): Int { val contValues = mapToContentValues(values) return db.update(tableName, contValues, where, params) @@ -59,7 +59,7 @@ class AndroidDatabase( override fun delete( tableName: String, where: String, - vararg params: String, + vararg params: String ) { db.delete(tableName, where, params) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabaseOpener.kt b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabaseOpener.kt index 923ae1bf7..96d010aca 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabaseOpener.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabaseOpener.kt @@ -30,7 +30,7 @@ class AndroidDatabaseOpener @Inject constructor() : DatabaseOpener { db = SQLiteDatabase.openDatabase( file.absolutePath, null, - SQLiteDatabase.OPEN_READWRITE, + SQLiteDatabase.OPEN_READWRITE ), file = file ) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt b/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt index 89efc00af..29027d9e2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/ActivityContextModule.kt @@ -25,5 +25,6 @@ import dagger.Provides @Module class ActivityContextModule( @get:Provides - @get:ActivityContext val context: Context + @get:ActivityContext + val context: Context ) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt b/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt index 74b433ea2..e7cc78f49 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/inject/AppContextModule.kt @@ -26,5 +26,6 @@ import dagger.Provides class AppContextModule( @get:Provides @get:AppContext - @param:AppContext val context: Context + @param:AppContext + val context: Context ) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt index 6be35b4c9..c3981baf2 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt @@ -53,8 +53,9 @@ class IntentParser var timestamp = intent.getLongExtra("timestamp", today) timestamp = DateUtils.getStartOfDay(timestamp) - if (timestamp < 0 || timestamp > today) + if (timestamp < 0 || timestamp > today) { throw IllegalArgumentException("timestamp is not valid") + } return Timestamp(timestamp) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt index 09d8f8b46..a63982358 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/AndroidNotificationTray.kt @@ -96,7 +96,6 @@ class AndroidNotificationTray timestamp: Timestamp, disableSound: Boolean = false ): Notification { - val addRepetitionAction = Action( R.drawable.ic_action_check, context.getString(R.string.yes), @@ -146,8 +145,9 @@ class AndroidNotificationTray .addAction(removeRepetitionAction) } - if (!disableSound) + if (!disableSound) { builder.setSound(ringtoneManager.getURI()) + } if (SDK_INT < Build.VERSION_CODES.S) { val snoozeAction = Action( diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt index 1e79ae857..0c30520d1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/RingtoneManager.kt @@ -61,8 +61,9 @@ class RingtoneManager "pref_ringtone_uri", defaultRingtoneUri.toString() )!! - if (prefRingtoneUri.isNotEmpty()) + if (prefRingtoneUri.isNotEmpty()) { ringtoneUri = Uri.parse(prefRingtoneUri) + } return ringtoneUri } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt index 42514b118..f7e532984 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/notifications/SnoozeDelayPickerActivity.kt @@ -33,7 +33,8 @@ import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.core.models.Habit -import org.isoron.uhabits.core.ui.ThemeSwitcher.Companion.THEME_LIGHT +import org.isoron.uhabits.core.ui.views.DarkTheme +import org.isoron.uhabits.core.ui.views.LightTheme import org.isoron.uhabits.receivers.ReminderController import org.isoron.uhabits.utils.SystemUtils import java.util.Calendar @@ -51,11 +52,8 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener { val app = applicationContext as HabitsApplication val appComponent = app.component val themeSwitcher = AndroidThemeSwitcher(this, appComponent.preferences) - if (themeSwitcher.getSystemTheme() == THEME_LIGHT) { - setTheme(R.style.BaseDialog) - } else { - setTheme(R.style.BaseDialogDark) - } + themeSwitcher.setTheme() + val data = intent.data if (data == null) { finish() @@ -75,6 +73,16 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener { SystemUtils.unlockScreen(this) } + private fun AndroidThemeSwitcher.setTheme() { + if (this.isNightMode) { + setTheme(R.style.BaseDialogDark) + this.currentTheme = DarkTheme() + } else { + setTheme(R.style.BaseDialog) + this.currentTheme = LightTheme() + } + } + private fun showTimePicker() { val calendar = Calendar.getInstance() val dialog = TimePickerDialog.newInstance( @@ -95,7 +103,9 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener { if (snoozeValues[position] >= 0) { reminderController!!.onSnoozeDelayPicked(habit!!, snoozeValues[position]) finish() - } else showTimePicker() + } else { + showTimePicker() + } } override fun finish() { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ExportDBTaskFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ExportDBTaskFactory.kt index 94481bb62..b1d031292 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ExportDBTaskFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ExportDBTaskFactory.kt @@ -27,7 +27,7 @@ import javax.inject.Inject class ExportDBTaskFactory @Inject constructor( @AppContext private val context: Context, - private val system: AndroidDirFinder, + private val system: AndroidDirFinder ) { fun create(listener: ExportDBTask.Listener) = ExportDBTask(context, system, listener) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ImportDataTaskFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ImportDataTaskFactory.kt index 5b3efe630..9a6287f02 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ImportDataTaskFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/tasks/ImportDataTaskFactory.kt @@ -27,7 +27,7 @@ import javax.inject.Inject class ImportDataTaskFactory @Inject constructor( private val importer: GenericImporter, - private val modelFactory: ModelFactory, + private val modelFactory: ModelFactory ) { fun create(file: File, listener: ImportDataTask.Listener) = ImportDataTask(importer, modelFactory, file, listener) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt index 7ab5a1e34..34205fd5c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/AttributeSetUtils.kt @@ -24,6 +24,7 @@ import org.jetbrains.annotations.Contract object AttributeSetUtils { const val ISORON_NAMESPACE = "http://isoron.org/android" + @JvmStatic fun getAttribute( context: Context, diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt index db25f279d..81ea121db 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DatabaseUtils.kt @@ -33,6 +33,7 @@ import java.text.SimpleDateFormat object DatabaseUtils { private var opener: HabitsDatabaseOpener? = null + @JvmStatic fun getDatabaseFile(context: Context): File { val databaseFilename = databaseFilename diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DialogUtils.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DialogUtils.kt index 855f865c7..a1aefe16f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/DialogUtils.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/DialogUtils.kt @@ -6,16 +6,24 @@ import androidx.fragment.app.FragmentManager import java.lang.ref.WeakReference var currentDialog: WeakReference = WeakReference(null) +var currentDialogFragment: WeakReference = WeakReference(null) -fun Dialog.dismissCurrentAndShow() { +fun dismissCurrentDialog() { currentDialog.get()?.dismiss() + currentDialog = WeakReference(null) + currentDialogFragment.get()?.dismiss() + currentDialogFragment = WeakReference(null) +} + +fun Dialog.dismissCurrentAndShow() { + dismissCurrentDialog() currentDialog = WeakReference(this) show() } fun DialogFragment.dismissCurrentAndShow(fragmentManager: FragmentManager, tag: String) { - currentDialog.get()?.dismiss() + dismissCurrentDialog() + currentDialogFragment = WeakReference(this) show(fragmentManager, tag) fragmentManager.executePendingTransactions() - currentDialog = WeakReference(this.dialog) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index 35a8cecbd..abf98970c 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -61,7 +61,6 @@ fun RelativeLayout.addBelow( height: Int = WRAP_CONTENT, applyCustomRules: (params: RelativeLayout.LayoutParams) -> Unit = {} ) { - view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(BELOW, subject.id) applyCustomRules(this) @@ -75,7 +74,6 @@ fun RelativeLayout.addAtBottom( width: Int = MATCH_PARENT, height: Int = WRAP_CONTENT ) { - view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_BOTTOM) } @@ -88,7 +86,6 @@ fun RelativeLayout.addAtTop( width: Int = MATCH_PARENT, height: Int = WRAP_CONTENT ) { - view.layoutParams = RelativeLayout.LayoutParams(width, height).apply { addRule(ALIGN_PARENT_TOP) } @@ -159,7 +156,7 @@ fun Activity.restartWithFade(cls: Class<*>?) { overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out) startActivity(Intent(this, cls)) }, - 500, + 500 ) // HACK: Let the menu disappear first } @@ -168,7 +165,7 @@ fun View.setupToolbar( title: String, color: PaletteColor, theme: Theme, - displayHomeAsUpEnabled: Boolean = true, + displayHomeAsUpEnabled: Boolean = true ) { toolbar.elevation = InterfaceUtils.dpToPixels(context, 2f) val res = StyledResources(context) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt index bc9654529..4dcdbb0f9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/BaseWidget.kt @@ -147,10 +147,11 @@ abstract class BaseWidget(val context: Context, val id: Int, val stacked: Boolea protected val preferedBackgroundAlpha: Int get() { - return if (stacked) + return if (stacked) { 255 - else + } else { prefs.widgetOpacity + } } init { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt index 66d1da842..017f67a29 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt @@ -33,7 +33,7 @@ open class CheckmarkWidget( context: Context, widgetId: Int, protected val habit: Habit, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, widgetId, stacked) { override val defaultHeight: Int = 125 @@ -41,7 +41,7 @@ open class CheckmarkWidget( override fun getOnClickPendingIntent(context: Context): PendingIntent? { return if (habit.isNumerical) { - pendingIntentFactory.showNumberPicker(habit, DateUtils.getToday()) + pendingIntentFactory.showNumberPicker(habit, DateUtils.getTodayWithOffset()) } else { pendingIntentFactory.toggleCheckmark(habit, null) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt index af8010014..ca9ebcd90 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidgetProvider.kt @@ -23,7 +23,10 @@ import android.content.Context class CheckmarkWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) CheckmarkWidget(context, id, habits[0]) - else StackWidget(context, id, StackWidgetType.CHECKMARK, habits) + return if (habits.size == 1) { + CheckmarkWidget(context, id, habits[0]) + } else { + StackWidget(context, id, StackWidgetType.CHECKMARK, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt index f96a93e48..7caf44fec 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/EmptyWidget.kt @@ -27,7 +27,7 @@ import org.isoron.uhabits.widgets.views.EmptyWidgetView class EmptyWidget( context: Context, widgetId: Int, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, widgetId, stacked) { override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt index 8b76cb1b3..88c6b7655 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidget.kt @@ -33,7 +33,7 @@ class FrequencyWidget( widgetId: Int, private val habit: Habit, private val firstWeekday: Int, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, widgetId, stacked) { override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt index 3d380ec25..698f002f4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/FrequencyWidgetProvider.kt @@ -24,12 +24,15 @@ import android.content.Context class FrequencyWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) FrequencyWidget( - context, - id, - habits[0], - preferences.firstWeekdayInt - ) - else StackWidget(context, id, StackWidgetType.FREQUENCY, habits) + return if (habits.size == 1) { + FrequencyWidget( + context, + id, + habits[0], + preferences.firstWeekdayInt + ) + } else { + StackWidget(context, id, StackWidgetType.FREQUENCY, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index 25d8b7348..659a89ee9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -36,7 +36,7 @@ class HistoryWidget( context: Context, id: Int, private val habit: Habit, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, id, stacked) { override val defaultHeight: Int = 250 @@ -53,7 +53,7 @@ class HistoryWidget( val model = HistoryCardPresenter.buildState( habit = habit, firstWeekday = prefs.firstWeekday, - theme = WidgetTheme(), + theme = WidgetTheme() ) (widgetView.dataView as AndroidDataView).apply { val historyChart = (this.view as HistoryChart) @@ -75,7 +75,7 @@ class HistoryWidget( firstWeekday = prefs.firstWeekday, series = listOf(), defaultSquare = HistoryChart.Square.OFF, - notesIndicators = listOf(), + notesIndicators = listOf() ) } ).apply { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt index c9dd8da66..ab6dbc9eb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidgetProvider.kt @@ -23,11 +23,14 @@ import android.content.Context class HistoryWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) HistoryWidget( - context, - id, - habits[0] - ) - else StackWidget(context, id, StackWidgetType.HISTORY, habits) + return if (habits.size == 1) { + HistoryWidget( + context, + id, + habits[0] + ) + } else { + StackWidget(context, id, StackWidgetType.HISTORY, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt index 14ccc1d30..8be9dfed5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidget.kt @@ -33,7 +33,7 @@ class ScoreWidget( context: Context, id: Int, private val habit: Habit, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, id, stacked) { override val defaultHeight: Int = 300 override val defaultWidth: Int = 300 @@ -46,7 +46,7 @@ class ScoreWidget( habit = habit, firstWeekday = prefs.firstWeekdayInt, spinnerPosition = prefs.scoreCardSpinnerPosition, - theme = WidgetTheme(), + theme = WidgetTheme() ) val widgetView = view as GraphWidgetView widgetView.setBackgroundAlpha(preferedBackgroundAlpha) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt index f271fb799..160054da1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/ScoreWidgetProvider.kt @@ -23,7 +23,10 @@ import android.content.Context class ScoreWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) ScoreWidget(context, id, habits[0]) - else StackWidget(context, id, StackWidgetType.SCORE, habits) + return if (habits.size == 1) { + ScoreWidget(context, id, habits[0]) + } else { + StackWidget(context, id, StackWidgetType.SCORE, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt index ab2bace27..6c59c1e1d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidget.kt @@ -34,7 +34,7 @@ class StackWidget( widgetId: Int, private val widgetType: StackWidgetType, private val habits: List, - stacked: Boolean = true, + stacked: Boolean = true ) : BaseWidget(context, widgetId, stacked) { override val defaultHeight: Int = 0 override val defaultWidth: Int = 0 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt index d23005c96..b8e2ba49b 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StackWidgetService.kt @@ -33,7 +33,7 @@ import org.isoron.uhabits.R import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitNotFoundException import org.isoron.uhabits.core.preferences.Preferences -import org.isoron.uhabits.core.utils.DateUtils.Companion.getToday +import org.isoron.uhabits.core.utils.DateUtils.Companion.getTodayWithOffset import org.isoron.uhabits.intents.IntentFactory import org.isoron.uhabits.intents.PendingIntentFactory import org.isoron.uhabits.utils.InterfaceUtils.dpToPixels @@ -101,7 +101,7 @@ internal class StackRemoteViewsFactory(private val context: Context, intent: Int val landscapeViews = widget.landscapeRemoteViews val portraitViews = widget.portraitRemoteViews val factory = PendingIntentFactory(context, IntentFactory()) - val intent = StackWidgetType.getIntentFillIn(factory, widgetType, h, habits, getToday()) + val intent = StackWidgetType.getIntentFillIn(factory, widgetType, h, habits, getTodayWithOffset()) landscapeViews.setOnClickFillInIntent(R.id.button, intent) portraitViews.setOnClickFillInIntent(R.id.button, intent) val remoteViews = RemoteViews(landscapeViews, portraitViews) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt index e07c95359..e997c54c6 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidget.kt @@ -34,7 +34,7 @@ class StreakWidget( context: Context, id: Int, private val habit: Habit, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, id, stacked) { override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt index 98b9e8dd9..5e9e8d7b3 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/StreakWidgetProvider.kt @@ -23,7 +23,10 @@ import android.content.Context class StreakWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) StreakWidget(context, id, habits[0]) - else StackWidget(context, id, StackWidgetType.STREAKS, habits) + return if (habits.size == 1) { + StreakWidget(context, id, habits[0]) + } else { + StackWidget(context, id, StackWidgetType.STREAKS, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt index f98331e8f..31a9d20d3 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidget.kt @@ -37,7 +37,7 @@ class TargetWidget( context: Context, id: Int, private val habit: Habit, - stacked: Boolean = false, + stacked: Boolean = false ) : BaseWidget(context, id, stacked) { override val defaultHeight: Int = 200 override val defaultWidth: Int = 200 @@ -53,7 +53,7 @@ class TargetWidget( val data = TargetCardPresenter.buildState( habit = habit, firstWeekday = prefs.firstWeekdayInt, - theme = WidgetTheme(), + theme = WidgetTheme() ) chart.setColor(WidgetTheme().color(habit.color).toInt()) chart.setTargets(data.targets) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt index cb14d61ca..920307bb1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/TargetWidgetProvider.kt @@ -23,7 +23,10 @@ import android.content.Context class TargetWidgetProvider : BaseWidgetProvider() { override fun getWidgetFromId(context: Context, id: Int): BaseWidget { val habits = getHabitsFromWidgetId(id) - return if (habits.size == 1) TargetWidget(context, id, habits[0]) - else StackWidget(context, id, StackWidgetType.TARGET, habits) + return if (habits.size == 1) { + TargetWidget(context, id, habits[0]) + } else { + StackWidget(context, id, StackWidgetType.TARGET, habits) + } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt index ff743816b..67ad8ae2d 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/HabitPickerDialog.kt @@ -24,7 +24,6 @@ import android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID import android.appwidget.AppWidgetManager.INVALID_APPWIDGET_ID import android.content.Intent import android.os.Bundle -import android.widget.AbsListView.CHOICE_MODE_MULTIPLE import android.widget.ArrayAdapter import android.widget.Button import android.widget.ListView @@ -34,7 +33,6 @@ import org.isoron.uhabits.R import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.core.preferences.WidgetPreferences import org.isoron.uhabits.widgets.WidgetUpdater -import java.util.ArrayList class BooleanHabitPickerDialog : HabitPickerDialog() { override fun shouldHideNumerical() = true @@ -88,20 +86,12 @@ open class HabitPickerDialog : Activity() { with(listView) { adapter = ArrayAdapter( context, - android.R.layout.simple_list_item_multiple_choice, + android.R.layout.simple_list_item_1, habitNames ) - choiceMode = CHOICE_MODE_MULTIPLE - itemsCanFocus = false - } - saveButton.setOnClickListener { - val selectedIds = mutableListOf() - for (i in 0..listView.count) { - if (listView.isItemChecked(i)) { - selectedIds.add(habitIds[i]) - } + setOnItemClickListener { parent, view, position, id -> + confirm(mutableListOf(habitIds[position])) } - confirm(selectedIds) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt index 57cff3ddb..6515542b0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.kt @@ -66,23 +66,21 @@ class CheckmarkWidgetView : HabitWidgetView { val res = StyledResources(context) val bgColor: Int val fgColor: Int + setShadowAlpha(0x4f) when (entryState) { YES_MANUAL, SKIP -> { bgColor = activeColor fgColor = res.getColor(R.attr.contrast0) - setShadowAlpha(0x4f) backgroundPaint!!.color = bgColor frame!!.setBackgroundDrawable(background) } YES_AUTO, NO, UNKNOWN -> { bgColor = res.getColor(R.attr.cardBgColor) fgColor = res.getColor(R.attr.contrast60) - setShadowAlpha(0x00) } else -> { bgColor = res.getColor(R.attr.cardBgColor) fgColor = res.getColor(R.attr.contrast60) - setShadowAlpha(0x00) } } ring.setPercentage(percentage) @@ -98,21 +96,23 @@ class CheckmarkWidgetView : HabitWidgetView { private val text: String get() = if (isNumerical) { (max(0, entryValue) / 1000.0).toShortString() - } else when (entryState) { - YES_MANUAL, YES_AUTO -> resources.getString(R.string.fa_check) - SKIP -> resources.getString(R.string.fa_skipped) - UNKNOWN -> { - run { - if (preferences!!.areQuestionMarksEnabled) { - return resources.getString(R.string.fa_question) - } else { - resources.getString(R.string.fa_times) + } else { + when (entryState) { + YES_MANUAL, YES_AUTO -> resources.getString(R.string.fa_check) + SKIP -> resources.getString(R.string.fa_skipped) + UNKNOWN -> { + run { + if (preferences!!.areQuestionMarksEnabled) { + return resources.getString(R.string.fa_question) + } else { + resources.getString(R.string.fa_times) + } } + resources.getString(R.string.fa_times) } - resources.getString(R.string.fa_times) + NO -> resources.getString(R.string.fa_times) + else -> resources.getString(R.string.fa_times) } - NO -> resources.getString(R.string.fa_times) - else -> resources.getString(R.string.fa_times) } override val innerLayoutId: Int @@ -126,7 +126,7 @@ class CheckmarkWidgetView : HabitWidgetView { } else { width = min(width, height) } - val textSize = min(0.2f * width, getDimension(context, R.dimen.smallerTextSize)) + val textSize = min(0.175f * width, getDimension(context, R.dimen.smallTextSize)) label.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize) if (isNumerical) { ring.setTextSize(textSize * 0.9f) @@ -141,7 +141,8 @@ class CheckmarkWidgetView : HabitWidgetView { } private fun init() { - val appComponent: HabitsApplicationComponent = (context.applicationContext as HabitsApplication).component + val appComponent: HabitsApplicationComponent = + (context.applicationContext as HabitsApplication).component preferences = appComponent.preferences ring = findViewById(R.id.scoreRing) as RingView label = findViewById(R.id.label) as TextView diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt index 85a219479..6756b8acd 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/HabitWidgetView.kt @@ -69,7 +69,7 @@ abstract class HabitWidgetView : FrameLayout { val shadowRadius = dpToPixels(context, 2f).toInt() val shadowOffset = dpToPixels(context, 1f).toInt() val shadowColor = Color.argb(shadowAlpha, 0, 0, 0) - val cornerRadius = dpToPixels(context, 5f) + val cornerRadius = dpToPixels(context, 12f) val radii = FloatArray(8) Arrays.fill(radii, cornerRadius) val shape = RoundRectShape(radii, null, null) diff --git a/uhabits-android/src/main/res/drawable/widget_button_background.xml b/uhabits-android/src/main/res/drawable/widget_button_background.xml index 9187c326a..a5d8b5fbf 100644 --- a/uhabits-android/src/main/res/drawable/widget_button_background.xml +++ b/uhabits-android/src/main/res/drawable/widget_button_background.xml @@ -28,7 +28,7 @@ - + diff --git a/uhabits-android/src/main/res/layout/checkmark_popup.xml b/uhabits-android/src/main/res/layout/checkmark_popup.xml index 72dc79786..e21c2fb54 100644 --- a/uhabits-android/src/main/res/layout/checkmark_popup.xml +++ b/uhabits-android/src/main/res/layout/checkmark_popup.xml @@ -21,8 +21,10 @@ -