Compare commits

..

183 Commits

Author SHA1 Message Date
97b98a872d EmptyListViewTest: Ignore non-deterministic test failures 2025-06-24 22:22:14 -05:00
862a851e1c EmptyListViewTest: Remove unused imports 2025-06-24 22:13:08 -05:00
804030f5c0 EmptyListViewTest: Instantiate view within each test method 2025-06-24 22:10:36 -05:00
08ab3c22ce Merge branch 'master' into dev 2025-06-24 21:37:32 -05:00
b58f836d8e Merge branch 'release/2.3.0' into dev 2025-06-24 21:28:24 -05:00
9ed4630f9b Merge branch 'release/2.3.0' 2025-06-24 21:25:14 -05:00
70dab74528 Bump version to 2.3.0 and update changelog 2025-06-23 22:23:55 -05:00
7e5d2fa207 Update Gradle and AGP versions to 8.11.1 and 8.9.2 2025-06-23 21:48:00 -05:00
0e432fb332 HistoryWidget: Increase padding; update widget images 2025-06-23 21:47:47 -05:00
897a236501 Widgets: Update test images 2025-03-23 19:41:31 -05:00
0cccecec77 Widgets: Update test images 2025-03-23 19:27:12 -05:00
f1ed875256 Further increase widget corner radius to match current Android style 2025-03-23 17:10:39 -05:00
e82bd47aab Increase minimum widget size to 50x50 and 100x100
Some Samsung phones were allowing graph widgets to occupy 1x2 or
2x1 grid cells, leading to very small text. This commit bumps up
the minimum widget size to 100x100 to ensure they always occupy at
least 2x2 cells. Tested on Pixel 4, Pixel 7 and Samsung Galaxy S24.

Closes #2118
2025-03-23 16:52:23 -05:00
e9517f7378 Bump targetSdk to 36 2025-03-23 07:22:36 -05:00
12cc70a51a Confetti: Always emit from checkmark, not popup button 2025-03-23 07:06:45 -05:00
fa670b19b7 HabitCardView: Fix confetti position in API 36+ 2025-03-22 23:03:59 -05:00
45b100aad9 build.sh: Make output dir 2025-03-22 15:26:28 -05:00
3c0c0b77ff build.sh: Update emulator path 2025-03-22 15:19:37 -05:00
66fa56ea62 Merge branch 'improve-gradle' into dev 2025-03-21 22:16:29 -05:00
951dabea8b Merge branch 'isse_1857_reset_measurable_entry' into dev 2025-03-21 21:41:55 -05:00
76b9dd8bd9 Checkmark popup: Minor changes to layout 2025-03-21 21:41:23 -05:00
f68510f860 Allow user to disable confetti animation 2025-03-21 21:29:49 -05:00
245b0eb4d6 Update translators 2025-03-21 21:05:17 -05:00
4a0599fce4 Update translations from Crowdin 2025-03-21 21:01:54 -05:00
abbfe87260 gradle: Remove deleted module 2025-03-21 21:01:39 -05:00
3330014fa9 Remove unused project dirs (uhabits-core-legacy, uhabits-ios, etc) 2025-03-21 20:38:12 -05:00
kalina559
cc720e3dcb Removed an unnecessary change 2025-02-18 23:19:20 +01:00
kalina559
6e3d06cff9 Corrected formatting in the layout file 2025-02-18 22:32:48 +01:00
kalina559
d458cbd47a COrrected formatting 2025-02-18 20:51:16 +01:00
kalina559
74ce269446 Added 'UNKNOWN' button for measurable habits 2025-02-18 20:47:12 +01:00
Jimly Asshiddiqy
9eb8624863 Migrate to KSP 2025-02-17 09:56:21 +07:00
Jimly Asshiddiqy
c4bc301fb2 Implement version catalog 2025-02-14 16:56:04 +07:00
Chris Smowton
107c898f51 Add repository now required for old kotlin-css-jvm versions
Gradle Plugin Portal was previously making kotlin-css-jvm 1.0.0-pre.148-kotlin-1.4.30 available by virtue of mirroring JCenter. Now that Gradle have stopped doing that in preparation for JCenter to go away, we need to retrieve the old version from a different repository.

If this is bumped forwards to Kotlin 1.5.0+ it will become possible to get the package from Central instead.
2025-02-08 22:11:53 -06:00
Abdul Majeed
4a7d7ef490 Added Streaks info for numeric habits 2025-02-08 22:07:28 -06:00
Abdul Majeed
13ecc2a386 Added Streaks info for numeric habits 2025-02-08 22:07:28 -06:00
Jakub Kalinowski
2296a49999 Corrected HabitTest 2025-02-08 21:58:41 -06:00
Jakub Kalinowski
303020a8c0 Never mark AT_MOST habits as completed for today 2025-02-08 21:58:41 -06:00
Jakub Kalinowski
37219cb13f Ignoring isCompleted for AT_MOST habits 2025-02-08 21:56:17 -06:00
CM
62d9d29e91 [Fix] Markdown linter problems (#2084)
* MD024

* MD033

* MD034

* MD036

* MD040

* MD045

* MD046

---------

Co-authored-by: MacroController <anonymous@github.com>
2025-02-08 21:48:23 -06:00
451b536e71 Upgrade dependencies 2025-02-08 21:37:16 -06:00
14dbf90c23 Upgrade Kotlin, AGP 2025-02-08 21:12:11 -06:00
280a5ddceb Bump targedSdk to 35 2025-02-08 20:58:23 -06:00
22331ed364 Remove dependabot 2025-02-08 07:43:10 -06:00
d0a45eb523 Merge pull request #2028 from getgo-nobugs/dev
Fix the misalignment of "About" page in RTL language
2025-02-08 07:38:03 -06:00
getgo-nobugs
fec73af665 Update styles.xml 2024-07-28 11:16:23 +08:00
fc9cc423d0 Multiple fixes to edge-to-edge display (API 35) 2024-05-20 20:30:09 -05:00
e7165d993f Make compatible with edge-to-edge (API 35) 2024-05-20 09:33:00 -05:00
732ec1c70a Update AGP; disable lint 2024-05-19 20:36:43 -05:00
e823cd5758 Update lint-baseline 2024-05-19 20:01:32 -05:00
46fe683d71 Merge pull request #1942 from foralost/#1941_DateUtilsTest_failing
#1941 DateUtils test fix
2024-04-04 22:03:46 -05:00
7f6248123c DateUtilsTest: Simplify getCalendarUTC 2024-04-04 21:55:01 -05:00
2024277ebe Merge branch 'dev' into #1941_DateUtilsTest_failing 2024-04-04 21:52:27 -05:00
c216fb01d6 Merge pull request #1785 from hiqua/android_lint_baseline
Check android lint violations against current baseline
2024-04-04 21:45:37 -05:00
7cb32f486b lint: disable GradleDependency 2024-04-04 21:36:51 -05:00
093591fbaf Update lint baseline 2024-04-04 21:24:09 -05:00
985234cdf3 Merge branch 'dev' into android_lint_baseline 2024-04-04 21:18:22 -05:00
06090e238a Merge branch 'feature/konfetti' into dev 2024-04-02 19:51:59 -05:00
e48452f724 Move showConfetti to ListHabitsScreen; use button location; other tweaks 2024-04-02 19:34:00 -05:00
dependabot[bot]
936986e110 Bump daggerVersion from 2.50 to 2.51.1
Bumps `daggerVersion` from 2.50 to 2.51.1.

Updates `com.google.dagger:dagger` from 2.50 to 2.51.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.50...dagger-2.51.1)

Updates `com.google.dagger:dagger-compiler` from 2.50 to 2.51.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.50...dagger-2.51.1)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-02 22:04:24 +02:00
dependabot[bot]
4b3910aea8 Bump com.google.guava:guava from 33.0.0-android to 33.1.0-android
Bumps [com.google.guava:guava](https://github.com/google/guava) from 33.0.0-android to 33.1.0-android.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 18:11:48 +02:00
foralost
10074ded32 UTC Calendar fix 2024-03-04 11:31:45 +01:00
Gokul K
1280e798d2 rendering only if layout and konfetti view exists - to avoid null reference errors 2024-02-03 23:14:58 -06:00
Gokul K
b09306e793 fixing another lint error 2024-02-03 23:14:58 -06:00
Gokul K
e30636a447 fixed ktlint erorrs and is building successfully now 2024-02-03 23:14:58 -06:00
Gokul K
ad8738180c fixing some comments from @hiqua 2024-02-03 23:14:58 -06:00
Gokul K
08410c59d0 introducing confetti animation using konfetti library 2024-02-03 23:14:58 -06:00
Manish Kumar Verma
ab86cee70b Fix: No notification when goal type is set to "maximum" (#1931) 2024-02-02 19:21:40 -06:00
dependabot[bot]
3a0603605b Bump androidx.annotation:annotation from 1.7.0 to 1.7.1
Bumps androidx.annotation:annotation from 1.7.0 to 1.7.1.

---
updated-dependencies:
- dependency-name: androidx.annotation:annotation
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 04:43:18 -06:00
dependabot[bot]
6a78b4d853 Bump daggerVersion from 2.48.1 to 2.50 (#1907)
Bumps `daggerVersion` from 2.48.1 to 2.50.

Updates `com.google.dagger:dagger` from 2.48.1 to 2.50
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.48.1...dagger-2.50)

Updates `com.google.dagger:dagger-compiler` from 2.48.1 to 2.50
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.48.1...dagger-2.50)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:34:40 -06:00
dependabot[bot]
fe43b1435d Bump ch.qos.logback:logback-classic from 1.4.13 to 1.4.14 (#1905)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.13 to 1.4.14.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.13...v_1.4.14)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:33:18 -06:00
dependabot[bot]
12503b8a6d Bump com.google.guava:guava from 32.1.3-android to 33.0.0-android (#1902)
Bumps [com.google.guava:guava](https://github.com/google/guava) from 32.1.3-android to 33.0.0-android.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:33:03 -06:00
dependabot[bot]
ef7f78bff0 Bump org.xerial:sqlite-jdbc from 3.42.0.0 to 3.45.1.0 (#1929)
Bumps [org.xerial:sqlite-jdbc](https://github.com/xerial/sqlite-jdbc) from 3.42.0.0 to 3.45.1.0.
- [Release notes](https://github.com/xerial/sqlite-jdbc/releases)
- [Changelog](https://github.com/xerial/sqlite-jdbc/blob/master/CHANGELOG)
- [Commits](https://github.com/xerial/sqlite-jdbc/compare/3.42.0.0...3.45.1.0)

---
updated-dependencies:
- dependency-name: org.xerial:sqlite-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:32:43 -06:00
dependabot[bot]
53c208ded5 Bump com.google.android.material:material from 1.10.0 to 1.11.0 (#1908)
Bumps [com.google.android.material:material](https://github.com/material-components/material-components-android) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/material-components/material-components-android/releases)
- [Commits](https://github.com/material-components/material-components-android/compare/1.10.0...1.11.0)

---
updated-dependencies:
- dependency-name: com.google.android.material:material
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:32:23 -06:00
dependabot[bot]
1bdc83e92f Bump org.mockito.kotlin:mockito-kotlin from 5.1.0 to 5.2.1 (#1906)
Bumps [org.mockito.kotlin:mockito-kotlin](https://github.com/mockito/mockito-kotlin) from 5.1.0 to 5.2.1.
- [Release notes](https://github.com/mockito/mockito-kotlin/releases)
- [Commits](https://github.com/mockito/mockito-kotlin/compare/5.1.0...5.2.1)

---
updated-dependencies:
- dependency-name: org.mockito.kotlin:mockito-kotlin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:32:08 -06:00
dependabot[bot]
680c1cdc76 Bump kotlinVersion from 1.9.21 to 1.9.22 (#1904)
Bumps `kotlinVersion` from 1.9.21 to 1.9.22.

Updates `org.jetbrains.kotlin.android` from 1.9.21 to 1.9.22

Updates `org.jetbrains.kotlin.kapt` from 1.9.21 to 1.9.22

Updates `org.jetbrains.kotlin.multiplatform` from 1.9.21 to 1.9.22

Updates `org.jetbrains.kotlin:kotlin-stdlib-jdk8` from 1.9.21 to 1.9.22
- [Release notes](https://github.com/JetBrains/kotlin/releases)
- [Changelog](https://github.com/JetBrains/kotlin/blob/master/ChangeLog.md)
- [Commits](https://github.com/JetBrains/kotlin/compare/v1.9.21...v1.9.22)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlin.android
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.jetbrains.kotlin.kapt
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.jetbrains.kotlin.multiplatform
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: org.jetbrains.kotlin:kotlin-stdlib-jdk8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:31:50 -06:00
dependabot[bot]
80916bac50 Bump actions/upload-artifact from 3 to 4 (#1901)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 04:31:37 -06:00
Leon Todd
a5e3e9b3cf Unset measurable habits (#1899) 2024-01-30 19:42:53 -06:00
248ba50a8e Reformat source code 2024-01-30 19:38:32 -06:00
Andreas Gebhardt
45a82b3c2d Changed Checkmark Widget Color on implicit check
As proposed in #615, the background is now solid color on implicit check but has a stroked checkmark instead of a full one.
2024-01-30 19:25:57 -06:00
770d1293dc Merge branch 'master' into dev 2024-01-30 19:15:48 -06:00
d10538e720 Merge branch 'release/2.2.0' 2024-01-30 19:15:12 -06:00
02e9e2384e Update CHANGELOG 2024-01-30 19:09:22 -06:00
Serhii K
b627ff4413 Use colorBackground property instead of splash screen lib 2024-01-30 19:06:43 -06:00
Serhii K
0683ea43f4 Fix splash screen background color in dark mode 2024-01-30 19:06:43 -06:00
08f77a5cae Merge branch 'master' into release/2.2.0 2023-12-01 18:31:53 -06:00
27df792775 Update CHANGELOG 2023-12-01 18:29:34 -06:00
Leonard Dizon
800f92f255 Create locales_config.xml for per-app language 2023-12-01 18:14:06 -06:00
dependabot[bot]
e06ed3ed7d Bump ch.qos.logback:logback-classic from 1.4.11 to 1.4.13 (#1882)
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.11 to 1.4.13.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.13)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:08:31 -06:00
dependabot[bot]
3bb119c6ed Bump com.github.triplet.play from 3.8.4 to 3.8.6 (#1879)
Bumps com.github.triplet.play from 3.8.4 to 3.8.6.

---
updated-dependencies:
- dependency-name: com.github.triplet.play
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:08:05 -06:00
dependabot[bot]
0762699a86 Bump org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0 (#1881)
Bumps org.apache.commons:commons-lang3 from 3.13.0 to 3.14.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:07:26 -06:00
dependabot[bot]
8837326d44 Bump com.opencsv:opencsv from 5.8 to 5.9 (#1880)
Bumps com.opencsv:opencsv from 5.8 to 5.9.

---
updated-dependencies:
- dependency-name: com.opencsv:opencsv
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:07:17 -06:00
dependabot[bot]
481a3d5784 Bump org.junit.jupiter:junit-jupiter from 5.10.0 to 5.10.1 (#1878)
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.10.0 to 5.10.1.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.10.0...r5.10.1)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 18:07:03 -06:00
8eff782f54 Update dependencies 2023-11-29 20:07:45 -06:00
c590734c42 Update dependencies 2023-11-29 19:54:00 -06:00
7e7f68282b Update Kotlin 2023-11-29 19:38:21 -06:00
4bd5cee17b Update libraries 2023-11-29 19:30:32 -06:00
b2421dc8b1 GH Actions: Increase number of attempts 2023-11-27 20:57:43 -06:00
93363bff96 GH Actions: Add API 34 2023-11-27 20:57:14 -06:00
d01044b203 GH Actions: Add API 34 2023-11-27 20:47:48 -06:00
70fe513e52 Bump targetSdk to 34 2023-11-27 20:43:34 -06:00
dee93fde8f Upgrade to AGP 8.1.4 2023-11-27 19:46:54 -06:00
f0ce05e06e API 34: Implement workaround to keep sticky notifications non-dismissible 2023-11-25 15:42:04 -06:00
4975ba2752 Add permission: USE_EXACT_ALARM 2023-11-25 15:30:29 -06:00
ed8c60e52f Implement runtime notification permission; bump targetSdk to 33 2023-11-25 07:12:16 -06:00
dependabot[bot]
7735247521 Bump daggerVersion from 2.48 to 2.48.1
Bumps `daggerVersion` from 2.48 to 2.48.1.

Updates `com.google.dagger:dagger` from 2.48 to 2.48.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.48...dagger-2.48.1)

Updates `com.google.dagger:dagger-compiler` from 2.48 to 2.48.1
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.48...dagger-2.48.1)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-06 16:07:22 +01:00
dependabot[bot]
b32a6ad1b8 Bump org.jlleitschuh.gradle.ktlint from 11.5.1 to 11.6.0
Bumps org.jlleitschuh.gradle.ktlint from 11.5.1 to 11.6.0.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle.ktlint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 14:18:03 +02:00
dependabot[bot]
21a512ae71 Bump androidx.annotation:annotation from 1.6.0 to 1.7.0
Bumps androidx.annotation:annotation from 1.6.0 to 1.7.0.

---
updated-dependencies:
- dependency-name: androidx.annotation:annotation
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 14:17:41 +02:00
dependabot[bot]
b0944d3f1c Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-10-01 14:17:26 +02:00
dependabot[bot]
8a9b719c50 Bump org.mockito.kotlin:mockito-kotlin from 2.2.11 to 5.1.0
Bumps [org.mockito.kotlin:mockito-kotlin](https://github.com/mockito/mockito-kotlin) from 2.2.11 to 5.1.0.
- [Release notes](https://github.com/mockito/mockito-kotlin/releases)
- [Commits](https://github.com/mockito/mockito-kotlin/compare/2.2.11...5.1.0)

---
updated-dependencies:
- dependency-name: org.mockito.kotlin:mockito-kotlin
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-20 22:04:01 +02:00
Quentin Hibon
ef7454ae75 Bump kotlin from 1.7.21 to 1.8.20 2023-09-20 21:04:38 +02:00
Quentin Hibon
b51f6abfce Target JVM 17 in uhabits-server 2023-09-20 21:04:38 +02:00
Quentin Hibon
a013635224 Bump mockito-kotlin from 4.1.0 to 5.0.0 2023-09-20 21:04:38 +02:00
Quentin Hibon
a9f028a34b Target JVM 11 2023-09-20 21:04:38 +02:00
Quentin Hibon
3b0fba12f5 Remove unused imports in datetimepicker 2023-09-20 21:04:38 +02:00
Quentin Hibon
4139f09fb7 Add @Deprecated when overriding @Deprecated methods 2023-09-20 21:04:38 +02:00
Quentin Hibon
248ff2ec62 Bump mockito-kotlin from 2.2.11 to 4.1.0 in -server 2023-09-20 21:04:38 +02:00
dependabot[bot]
cc7178eb21 Bump daggerVersion from 2.47 to 2.48
Bumps `daggerVersion` from 2.47 to 2.48.

Updates `com.google.dagger:dagger` from 2.47 to 2.48
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.47...dagger-2.48)

Updates `com.google.dagger:dagger-compiler` from 2.47 to 2.48
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.47...dagger-2.48)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-09-04 14:47:47 +02:00
6116ef9450 Merge branch 'hotfix/2.1.3' 2023-08-28 05:51:08 -05:00
8801960615 Update CHANGELOG 2023-08-28 05:43:12 -05:00
b0a4284b66 NumberDialog: Use text input on Samsung devices
Fixes #1719
2023-08-28 05:36:59 -05:00
Felix Schlegel
334dabb407 Use default locale instead of hardcoded US locale (#1763) 2023-08-18 18:35:54 +02:00
dependabot[bot]
b2fc79a3ab Bump com.github.triplet.play from 3.7.0 to 3.8.4
Bumps com.github.triplet.play from 3.7.0 to 3.8.4.

---
updated-dependencies:
- dependency-name: com.github.triplet.play
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 22:56:02 +02:00
dependabot[bot]
f0e8643e6b Bump com.google.android.material:material from 1.8.0 to 1.9.0
Bumps [com.google.android.material:material](https://github.com/material-components/material-components-android) from 1.8.0 to 1.9.0.
- [Release notes](https://github.com/material-components/material-components-android/releases)
- [Commits](https://github.com/material-components/material-components-android/compare/1.8.0...1.9.0)

---
updated-dependencies:
- dependency-name: com.google.android.material:material
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 21:30:23 +02:00
dependabot[bot]
5cd616f967 Bump org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm
Bumps [org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm](https://github.com/Kotlin/kotlinx.coroutines) from 1.6.4 to 1.7.3.
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.6.4...1.7.3)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 21:14:34 +02:00
dependabot[bot]
b53ef758ec Bump ch.qos.logback:logback-classic from 1.4.5 to 1.4.9
Bumps [ch.qos.logback:logback-classic](https://github.com/qos-ch/logback) from 1.4.5 to 1.4.9.
- [Commits](https://github.com/qos-ch/logback/compare/v_1.4.5...v_1.4.9)

---
updated-dependencies:
- dependency-name: ch.qos.logback:logback-classic
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 21:00:20 +02:00
dependabot[bot]
5add03bf23 Bump org.junit.jupiter:junit-jupiter from 5.8.1 to 5.10.0
Bumps [org.junit.jupiter:junit-jupiter](https://github.com/junit-team/junit5) from 5.8.1 to 5.10.0.
- [Release notes](https://github.com/junit-team/junit5/releases)
- [Commits](https://github.com/junit-team/junit5/compare/r5.8.1...r5.10.0)

---
updated-dependencies:
- dependency-name: org.junit.jupiter:junit-jupiter
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 20:04:53 +02:00
Quentin Hibon
b465ee588b Update dependabot.yml
Increase PR limit from 5 (default) to 10 for gradle
2023-08-08 19:48:04 +02:00
dependabot[bot]
b9253d41ea Bump daggerVersion from 2.46 to 2.47
Bumps `daggerVersion` from 2.46 to 2.47.

Updates `com.google.dagger:dagger` from 2.46 to 2.47
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.46...dagger-2.47)

Updates `com.google.dagger:dagger-compiler` from 2.46 to 2.47
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.46...dagger-2.47)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 19:45:56 +02:00
dependabot[bot]
ca0a9dd85f Bump org.xerial:sqlite-jdbc from 3.40.0.0 to 3.42.0.0
Bumps [org.xerial:sqlite-jdbc](https://github.com/xerial/sqlite-jdbc) from 3.40.0.0 to 3.42.0.0.
- [Release notes](https://github.com/xerial/sqlite-jdbc/releases)
- [Changelog](https://github.com/xerial/sqlite-jdbc/blob/master/CHANGELOG)
- [Commits](https://github.com/xerial/sqlite-jdbc/compare/3.40.0.0...3.42.0.0)

---
updated-dependencies:
- dependency-name: org.xerial:sqlite-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 14:59:14 +02:00
dependabot[bot]
9951525cbe Bump com.opencsv:opencsv from 5.7.1 to 5.8
Bumps com.opencsv:opencsv from 5.7.1 to 5.8.

---
updated-dependencies:
- dependency-name: com.opencsv:opencsv
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 14:19:54 +02:00
dependabot[bot]
98b2c9cce2 Bump com.google.guava:guava from 31.1-android to 32.1.2-android
Bumps [com.google.guava:guava](https://github.com/google/guava) from 31.1-android to 32.1.2-android.
- [Release notes](https://github.com/google/guava/releases)
- [Commits](https://github.com/google/guava/commits)

---
updated-dependencies:
- dependency-name: com.google.guava:guava
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 14:19:42 +02:00
dependabot[bot]
19de2a2d1c Bump androidx.annotation:annotation from 1.5.0 to 1.6.0
Bumps androidx.annotation:annotation from 1.5.0 to 1.6.0.

---
updated-dependencies:
- dependency-name: androidx.annotation:annotation
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 09:31:17 +02:00
Quentin Hibon
80f783b669 Bump mockito-kotlin from 2.2.11 to 4.1.0 2023-08-08 02:44:41 +02:00
dependabot[bot]
761fe59c5e Bump commons-codec:commons-codec from 1.15 to 1.16.0
Bumps [commons-codec:commons-codec](https://github.com/apache/commons-codec) from 1.15 to 1.16.0.
- [Changelog](https://github.com/apache/commons-codec/blob/master/RELEASE-NOTES.txt)
- [Commits](https://github.com/apache/commons-codec/compare/rel/commons-codec-1.15...rel/commons-codec-1.16.0)

---
updated-dependencies:
- dependency-name: commons-codec:commons-codec
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 01:35:57 +02:00
dependabot[bot]
f58d8a52ff Bump kxCoroutinesVersion from 1.6.4 to 1.7.3
Bumps `kxCoroutinesVersion` from 1.6.4 to 1.7.3.

Updates `org.jetbrains.kotlinx:kotlinx-coroutines-android` from 1.6.4 to 1.7.3
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.6.4...1.7.3)

Updates `org.jetbrains.kotlinx:kotlinx-coroutines-core` from 1.6.4 to 1.7.3
- [Release notes](https://github.com/Kotlin/kotlinx.coroutines/releases)
- [Changelog](https://github.com/Kotlin/kotlinx.coroutines/blob/master/CHANGES.md)
- [Commits](https://github.com/Kotlin/kotlinx.coroutines/compare/1.6.4...1.7.3)

---
updated-dependencies:
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-android
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: org.jetbrains.kotlinx:kotlinx-coroutines-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 00:56:48 +02:00
dependabot[bot]
f4e5b68258 Bump org.apache.commons:commons-lang3 from 3.12.0 to 3.13.0
Bumps org.apache.commons:commons-lang3 from 3.12.0 to 3.13.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-lang3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-08 00:26:32 +02:00
dependabot[bot]
5df3ee0d61 Bump org.jlleitschuh.gradle.ktlint from 11.4.2 to 11.5.1
Bumps org.jlleitschuh.gradle.ktlint from 11.4.2 to 11.5.1.

---
updated-dependencies:
- dependency-name: org.jlleitschuh.gradle.ktlint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-07 23:32:18 +02:00
Quentin Hibon
25cff3d9b0 Check android lint violations against current baseline 2023-08-07 23:04:46 +02:00
dependabot[bot]
9f66a27b82 Bump com.android.tools:desugar_jdk_libs from 1.2.2 to 2.0.3
Bumps [com.android.tools:desugar_jdk_libs](https://github.com/google/desugar_jdk_libs) from 1.2.2 to 2.0.3.
- [Release notes](https://github.com/google/desugar_jdk_libs/releases)
- [Changelog](https://github.com/google/desugar_jdk_libs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/desugar_jdk_libs/commits)

---
updated-dependencies:
- dependency-name: com.android.tools:desugar_jdk_libs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-08-06 22:46:51 +02:00
Quentin Hibon
4bbb20e18e Remove android extensions (deprecated) 2023-08-03 22:55:05 +02:00
Quentin Hibon
4f9ab6d263 Migrate EditHabitActivity to view bindings 2023-08-03 22:55:05 +02:00
Quentin Hibon
af21fd25db Migrate FrequencyPickerDialog to view bindings 2023-08-03 22:55:05 +02:00
Quentin Hibon
35097e1263 Bump targetSdk to 32 2023-08-03 19:07:34 +02:00
Quentin Hibon
8e4274d923 Use assertThrows instead of ExpectedException 2023-08-03 19:07:04 +02:00
Quentin Hibon
12649141b1 Migrate junit.framework.Assert.assertEquals to kotlin.test.assertEquals
Also fix some warnings, e.g. shadowed variables.
2023-08-03 19:07:04 +02:00
Quentin Hibon
0526d37fbd Use official version of mockito-kotlin 2023-07-26 10:01:41 +02:00
Quentin Hibon
b083899ec8 Make AGP version explicit
This makes it possible to run the AGP upgrade assistant from Android Studio.
2023-07-26 09:47:02 +02:00
Quentin Hibon
6b793c7c16 Bump com.android.application from 7.3.1 to 7.4.2 2023-07-25 20:25:34 +02:00
Quentin Hibon
11ca993a75 Bump org.jlleitschuh.gradle.ktlint from 11.0.0 to 11.4.2
Also run ./gradlew ktlintFormat to follow new format.
2023-07-25 17:37:59 +02:00
Quentin Hibon
7348ddeffa Bump minSdk back to 28 from 23 (#1759)
Fixes #1758.
2023-07-10 18:06:59 -05:00
88df8d2552 Format source code 2023-07-08 17:13:45 -05:00
d4f4f8b4a9 Prevent crash if exact alarm permission is revoked 2023-06-05 20:25:00 -05:00
9ca1aa911a Minor layout fixes 2023-06-05 20:11:50 -05:00
ba57ebad31 Fix an invisible color in widgets; adjust another color 2023-06-05 20:01:41 -05:00
dependabot[bot]
e4d2c93a1d Bump actions/upload-artifact from 2 to 3 (#1724)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-04 18:40:58 -05:00
Ezio Melotti
07065a60ad Add "github-actions" ecosystem to dependabot.yml (#1716) 2023-06-04 18:37:35 -05:00
Jean-Baptiste
916cd76be1 Update checkout actions (#1715) 2023-06-04 18:35:08 -05:00
8b55ffb147 Fix timezone bug in MidnightTimer; increase logging 2023-06-04 18:25:33 -05:00
727e88b7b1 Fix skip button in locales that use comma instead of dot
Fixes #1721
2023-06-04 17:30:38 -05:00
f70d33878c Remove obsolete permission 2023-05-27 19:55:07 -05:00
6a55d3c01a Merge branch 'master' into dev 2023-05-27 16:14:03 -05:00
69b5ed3a6d Merge branch 'hotfix/2.1.2' 2023-05-27 15:38:27 -05:00
8b2adbf301 GH Actions: Remove API 23 2023-05-27 13:26:11 -05:00
88cc3a2a12 Update CHANGELOG 2023-05-26 20:12:06 -05:00
26526a71a9 Update test screenshots 2023-05-26 19:56:01 -05:00
11eb3713e5 Reschedule reminders on resume 2023-05-26 19:55:53 -05:00
1df9cc7664 Widgets: Remove option to create StackWidgets
StackWidgets have been unfortunately been very unreliable on multiple phones,
and fixing it does not appear to be simple. This commit removes the ability
to create new StackWidgets, but existing ones should remain functional.
2023-05-01 18:52:53 -05:00
dependabot[bot]
499eb467cb Bump daggerVersion from 2.44.2 to 2.46
Bumps `daggerVersion` from 2.44.2 to 2.46.

Updates `com.google.dagger:dagger` from 2.44.2 to 2.46
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.44.2...dagger-2.46)

Updates `com.google.dagger:dagger-compiler` from 2.44.2 to 2.46
- [Release notes](https://github.com/google/dagger/releases)
- [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md)
- [Commits](https://github.com/google/dagger/compare/dagger-2.44.2...dagger-2.46)

---
updated-dependencies:
- dependency-name: com.google.dagger:dagger
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.google.dagger:dagger-compiler
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-01 10:00:19 +02:00
dependabot[bot]
9d4df73c56 Bump androidx.test.ext:junit from 1.1.4 to 1.1.5
Bumps androidx.test.ext:junit from 1.1.4 to 1.1.5.

---
updated-dependencies:
- dependency-name: androidx.test.ext:junit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-08 11:58:02 +02:00
dependabot[bot]
d0f32dfa0a Bump espressoVersion from 3.5.0 to 3.5.1
Bumps `espressoVersion` from 3.5.0 to 3.5.1.

Updates `androidx.test.espresso:espresso-contrib` from 3.5.0 to 3.5.1

Updates `androidx.test.espresso:espresso-core` from 3.5.0 to 3.5.1

---
updated-dependencies:
- dependency-name: androidx.test.espresso:espresso-contrib
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: androidx.test.espresso:espresso-core
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-08 11:57:47 +02:00
Adrian Miozga
c609eceefc Update Play Store and F-Droid badges (#1668)
* Update Play Store and F-Droid badges

* Increase size of badges
2023-03-26 12:48:53 -05:00
Quentin Hibon
eb68220b8d Remove dependency on kotlin stdlib (#1669)
According to:
https://kotlinlang.org/docs/whatsnew14.html#dependency-on-the-standard-library-added-by-default
the explicit dependency is no longer needed.
2023-03-26 12:48:12 -05:00
b76da35752 Widgets: Increase corner radius to match Android 12 2023-03-24 05:24:58 -05:00
abead88ceb GH Actions: Fix build.sh 2023-03-23 04:48:40 -05:00
908eb4ac99 Convert NumberDialog to AppCompatDialogFragment; remove unused classes 2023-03-18 05:04:43 -05:00
71a05d598a CheckmarkDialog: Switch to AppCompatDialogFragment
Fixes issues with the soft keyboard covering the popup.
2023-01-30 05:59:42 -06:00
2131fb3a3d EntryList: Copy notes from original entries
Fixes #1566
2023-01-24 05:59:23 -06:00
1470dcd560 Remove toggle delay 2023-01-23 03:50:38 -06:00
471f977209 Replace some incorrect usages of getToday by getTodayWithOffset
Fixes #1541
2022-10-22 17:11:59 -05:00
2ba5f5fb98 Dismiss current dialog onPause
Fixes #1545
2022-10-22 16:19:49 -05:00
4de67bd27a GH Actions: Remove API 27 2022-10-22 16:01:36 -05:00
0bb82a48a5 NumberPopup: Accept comma (instead of dot) in certain locales
Fixes #1532
2022-10-22 15:44:30 -05:00
d5a5273607 Bump version to 2.1.2 2022-10-22 15:25:42 -05:00
516 changed files with 12354 additions and 16657 deletions

View File

@@ -1,6 +0,0 @@
version: 2
updates:
- package-ecosystem: "gradle"
directory: "/"
schedule:
interval: "monthly"

View File

@@ -12,17 +12,17 @@ jobs:
timeout-minutes: 30
steps:
- name: Check out source code
uses: actions/checkout@v1
uses: actions/checkout@v4
- name: Build project
run: ./build.sh build
- name: Run Android tests
run: ./build.sh android-tests-parallel 28 29 30 31 32 33
run: ./build.sh android-tests-parallel 28 29 30 32 33 34
- name: Upload artifacts
if: always()
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: build
path: |

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ node_modules
*xcuserdata*
*.sketch
crowdin.yml
kotlin-js-store

View File

@@ -1,5 +1,53 @@
# Changelog
## [2.3.0] -- 2025-06-23
### Added
- Add support for Android 15 and 16 (@iSoron)
- Show confetti animation (@gokulk16, @iSoron, #1743)
- Show streaks for measurable habits (@teckwarz, #2059)
- Allow user to unset measurable habits (@leontodd, @kalina559, #1899, #2109)
### Changed
- Change background widget color for habits with implicit checks (@wobbba, #1915)
### Fixed
- Fix notification when goal type is set to maximum (@manish99verma, #1931)
- Never mark "at most" habits as completed for the day (@kalina559, #2077)
- Increase minimum widget size (@iSoron, #2118)
- Improve Gradle configuration (@jimlyas, #2108)
## [2.2.0] -- 2024-01-30
### Added
- Add support for Android 14 (@iSoron, @hiqua)
- Allow user to change app language (@leondzn)
### Fixed
- Implement workaround to make notifications non-dismissible in Android 14 (@iSoron, #1872)
- Fix splash screen background color in dark mode (@SIKV, #1888)
## [2.1.3] -- 2023-08-28
### Fixed
- Use text input on Samsung devices (@iSoron, #1719)
- Prevent crash if alarm permission is revoked (@iSoron)
- Adjust widget colors (@iSoron)
- Fix bug preventing screens from updating at midnight (@iSoron)
- Fix skip button in locales that use comma instead of dot (@iSoron, #1721)
## [2.1.2] -- 2023-05-26
### Fixed
- Fix bug that caused widget to enter checkmark on wrong date (@iSoron, #1541)
- 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)

View File

@@ -1,6 +1,6 @@
# Copyright Notices
### ActiveAndroid
## ActiveAndroid
<https://github.com/pardom/ActiveAndroid>
@@ -18,7 +18,7 @@
See the License for the specific language governing permissions and
limitations under the License.
### Android Open Source Project
## Android Open Source Project
<https://source.android.com/>
@@ -36,7 +36,7 @@
See the License for the specific language governing permissions and
limitations under the License.
### FontAwesome
## FontAwesome
<http://fontawesome.io>
@@ -59,7 +59,7 @@ under the SIL OFL 1.1.
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
### Material Design Icons
## Material Design Icons
<https://github.com/google/material-design-icons>
@@ -67,7 +67,7 @@ Material design icons are the official icon set from Google that are designed
under the material design guidelines. Available under the Creative Common
Attribution 4.0 International License (CC-BY 4.0).
### Android Flow Layout
## Android Flow Layout
<https://github.com/ApmeM/android-flowlayout>
@@ -87,7 +87,7 @@ Extended linear layout that wrap its content when there is no place in the curre
License for the specific language governing permissions and limitations
under the License.
### Dagger 2
## Dagger 2
<https://github.com/google/dagger>
@@ -108,7 +108,7 @@ A fast dependency injector for Android and Java.
See the License for the specific language governing permissions and
limitations under the License.
### AutoFactory
## AutoFactory
<https://github.com/google/auto/tree/master/factory>
@@ -128,7 +128,7 @@ A source code generator for JSR-330-compatible factories.
See the License for the specific language governing permissions and
limitations under the License.
### Retrolambda
## Retrolambda
<https://github.com/orfjackal/retrolambda>
@@ -138,7 +138,7 @@ Backport of Java 8's lambda expressions to Java 7, 6 and 5
This software is released under the Apache License 2.0.
The license text is at http://www.apache.org/licenses/LICENSE-2.0
### PebbleKit SDK
## PebbleKit SDK
<https://github.com/pebble/pebble-android-sdk/>
@@ -147,7 +147,7 @@ Android PebbleKit SDK to talk to the Pebble via Bluetooth
The MIT License (MIT)
Copyright (c) 2014 - 2015 Pebble Technology
### AppIntro
## AppIntro
<https://github.com/PaoloRotolo/AppIntro>
@@ -168,7 +168,7 @@ Make a cool intro for your Android app.
See the License for the specific language governing permissions and
limitations under the License.
### ButterKnife
## ButterKnife
<https://github.com/JakeWharton/butterknife>
@@ -188,7 +188,7 @@ Bind Android views and callbacks to fields and methods
See the License for the specific language governing permissions and
limitations under the License.
### opencsv
## opencsv
<http://opencsv.sourceforge.net/>

View File

@@ -1,13 +1,13 @@
<h1 align="center">Loop Habit Tracker</h1>
<p align="center">
<a href="https://github.com/iSoron/uhabits/actions?query=workflow%3A%22Build+%26+Test%22">
<img src="https://github.com/iSoron/uhabits/workflows/Build%20&%20Test/badge.svg" />
<img alt="Build & Test" src="https://github.com/iSoron/uhabits/workflows/Build%20&%20Test/badge.svg" />
</a>
<a href="https://github.com/iSoron/uhabits/releases/latest">
<img src="https://img.shields.io/github/v/release/iSoron/uhabits" />
<img alt="release" src="https://img.shields.io/github/v/release/iSoron/uhabits" />
</a>
<a href="https://github.com/iSoron/uhabits/discussions">
<img src="https://img.shields.io/badge/GitHub-Discussions-%23fc4ebc" />
<img alt="GitHub" src="https://img.shields.io/badge/GitHub-Discussions-%23fc4ebc" />
</a>
</p>
@@ -17,8 +17,8 @@ show you how your habits improved over time. It is completely ad-free and open
source.
<p align="center">
<a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/apps/en-play-badge-border.png" height="75px"/></a>
<a href="https://f-droid.org/app/org.isoron.uhabits"><img alt="Get it on F-Droid" src="https://i.imgur.com/baSPE7X.png" height="75px"/></a>
<a href="https://play.google.com/store/apps/details?id=org.isoron.uhabits&utm_source=global_co&utm_medium=prtnr&utm_content=Mar2515&utm_campaign=PartBadge&pcampaignid=MKT-AC-global-none-all-co-pr-py-PartBadges-Oct1515-1"><img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" height="80px"/></a>
<a href="https://f-droid.org/app/org.isoron.uhabits"><img alt="Get it on F-Droid" src="https://f-droid.org/badge/get-it-on.png" height="80px"/></a>
</p>
## Screenshots
@@ -32,32 +32,23 @@ source.
## Features
* <b>Beautiful, minimalistic and lightweight interface.</b>
Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones.
* **Beautiful, minimalistic and lightweight interface.** Loop has an elegant and minimalistic interface that is very easy to use, even for first-time users. Highly optimized for speed, the app works well even on older phones.
* <b>Habit score.</b>
Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps.
* **Habit score.** Loop has an advanced formula for calculating the strength of your habits. Every repetition makes your habit stronger and every missed day makes it weaker. A few missed days after a long streak, however, will not completely destroy your progress, unlike many other don't-break-the-chain apps.
* <b>Flexible schedules.</b>
In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day.
* **Flexible schedules.** In addition to daily habits, Loop supports habits with more complex schedules, such as 3 times per week or every other day.
* <b>Reminders.</b>
Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification.
* **Reminders.** Schedule notifications to remind you of your habits. Each habit can have its own reminder, at a chosen time of the day. Easily check or dismiss your habit directly from the notification.
* <b>Widgets.</b>
Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app.
* **Widgets.** Be reminded of your habits whenever you unlock your phone. Colorful widgets allow you to track your habits directly from your home screen, without even opening the app.
* <b>Take control of your data.</b>
If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker.
* **Take control of your data.** If you want to further analyze your data, or move it to another service, Loop allows you to export it to spreadsheets (CSV) or to a database file (SQLite). For power users, checkmarks can be added through other apps, such as Tasker.
* <b>No limitations.</b>
Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases.
* **No limitations.** Track as many habits as you wish. Loop imposes no artificial limits on how many habits you can have. All features are available to all users. There are no in-app purchases.
* <b>Completely ad-free and open source.</b>
There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3).
* **Completely ad-free and open source.** There are no advertisements, annoying notifications or intrusive permissions in this app, and there will never be. The app is completely open-source (GPLv3).
* <b>Works offline and respects your privacy.</b>
Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it.
* **Works offline and respects your privacy.** Loop doesn't require an Internet connection or online account registration. Your confidential data is never sent to anyone. Neither the developers nor any third-parties have access to it.
## Installing
@@ -94,7 +85,7 @@ contribute, even if you are not a software developer.
## License
<img align="right" src="https://www.gnu.org/graphics/gplv3-88x31.png">
<img align="right" alt="GPL v3" src="https://www.gnu.org/graphics/gplv3-88x31.png">
Copyright (C) 2016-2021 Álinson Santos Xavier <isoron@gmail.com>

View File

@@ -1,23 +1,11 @@
plugins {
val kotlinVersion = "1.7.21"
id("com.android.application") version ("7.3.1") 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"
alias(libs.plugins.agp) apply false
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.ktlint.plugin) apply false
alias(libs.plugins.shadow) apply false
}
apply {
from("translators.gradle.kts")
}
allprojects {
repositories {
google()
mavenCentral()
maven(url = "https://plugins.gradle.org/m2/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
maven(url = "https://jitpack.io")
}
from("gradle/translators.gradle.kts")
}

View File

@@ -21,7 +21,7 @@ ADB="${ANDROID_HOME}/platform-tools/adb"
ANDROID_OUTPUTS_DIR="uhabits-android/build/outputs"
AVDMANAGER="${ANDROID_HOME}/cmdline-tools/latest/bin/avdmanager"
AVD_PREFIX="uhabitsTest"
EMULATOR="${ANDROID_HOME}/tools/emulator"
EMULATOR="${ANDROID_HOME}/emulator/emulator"
GRADLE="./gradlew --stacktrace --quiet"
PACKAGE_NAME=org.isoron.uhabits
SDKMANAGER="${ANDROID_HOME}/cmdline-tools/latest/bin/sdkmanager"
@@ -38,6 +38,11 @@ if [ ! -f "${ANDROID_HOME}/platform-tools/adb" ]; then
exit 1
fi
if [ ! -f "$EMULATOR" ]; then
echo "Error: Not found: $EMULATOR"
exit 1
fi
# Logging
# -----------------------------------------------------------------------------
@@ -64,6 +69,7 @@ fail() {
core_build() {
log_info "Building uhabits-core..."
$GRADLE ktlintCheck || fail
$GRADLE lintDebug || fail
$GRADLE :uhabits-core:build || fail
}
@@ -181,7 +187,7 @@ android_test() {
OUT_INSTRUMENT=${ANDROID_OUTPUTS_DIR}/instrument-${API}.txt
OUT_LOGCAT=${ANDROID_OUTPUTS_DIR}/logcat-${API}.txt
FAILED_TESTS=""
for i in {1..5}; do
for i in {1..10}; do
log_info "Running $size instrumented tests (attempt $i)..."
$ADB shell am instrument \
-r -e coverage true -e size "$size" $FAILED_TESTS \
@@ -216,21 +222,30 @@ android_test_parallel() {
for API in $*; do
(
LOG=build/android-test-$API.log
mkdir -p build
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 +255,7 @@ android_test_parallel() {
echo "::endgroup::"
done
return $RET_CODE
return $success
}
android_build() {

View File

@@ -9,17 +9,17 @@ This pages describes how to download and build the app from the source code. If
## Build using Android Studio
**Step 1: Install git**
### Step 1: Install git
The package `git` is required for downloading the source code of the app and submitting changes GitHub. Please see [the git book](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) for further instructions. If you are planning to submit pull requests in the future, it is recommended to [generate and configure your SSH keys](https://help.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent).
**Step 2: Download and install Android Studio**
### Step 2: Download and install Android Studio
Although Android Studio can be downloaded [from their official website](https://developer.android.com/studio/), a much better option is to install it through [JetBrains Toolbox](https://www.jetbrains.com/toolbox-app/). This tool, developed by the same developers of Android Studio, allows you to easily upgrade and downgrade the IDE, or switch between stable, beta and canary versions. After downloading and installing JetBrains Toolbox, simply click the install button near Android Studio to install the newest stable version of IDE. Beta and canary versions have not been tested and may not work correctly.
After installation, launch Android Studio. If this is the first time you launch it, you will need to go through a wizard to setup the IDE. The default options should work fine. The wizard will download all additional components necessary for development, including the emulator, so it may take a while.
**Step 3: Download the source code**
### Step 3: Download the source code
To create a complete copy of the source code repository, open the terminal (Linux/macOS) or Git Bash (Windows), navigate to the desired folder, then run:
```bash
@@ -27,7 +27,7 @@ git clone https://github.com/iSoron/uhabits.git
```
The repository will be downloaded to the directory `uhabits`.
**Step 4: Open and run the project on Android Studio**
### Step 4: Open and run the project on Android Studio
1. Launch Android Studio and select "Open an existing Android Studio project".
2. When the IDE asks you for the project location, select `uhabits` and click "Ok".
@@ -41,7 +41,7 @@ The repository will be downloaded to the directory `uhabits`.
The following instructions were tested on **Ubuntu Linux 18.04 LTS** and may need to be modified for other operating systems.
**Step 1: Install basic packages**
### Step 1: Install basic packages
To build the application, some basic packages are required. The package `git` is required to download the source code, while `openjdk-8-jdk-headless` is required for compiling Java and Kotlin files.
@@ -53,14 +53,14 @@ sudo apt-get install -y git openjdk-8-jdk-headless
**IMPORTANT:** Newer JDK versions have not been tested and may not work correctly.
**Step 2: Install Android SDK tools**
### Step 2: Install Android SDK tools
The Android SDK tools contains many necessary tools for developing and debugging Android applications. It can be obtained as part of Android Studio, but, for simple command line usage, it can also be downloaded individually.
1. Download the file `sdk-tools-linux-4333796.zip` (or a newer version) from https://developer.android.com/studio/#downloads, and extract it somewhere. In this guide, we assume that it was extracted to `/opt/android-sdk/tools`; that is, the script `/opt/android-sdk/tools/bin/sdkmanager` should exist.
1. Download the file `sdk-tools-linux-4333796.zip` (or a newer version) from <https://developer.android.com/studio/#downloads>, and extract it somewhere. In this guide, we assume that it was extracted to `/opt/android-sdk/tools`; that is, the script `/opt/android-sdk/tools/bin/sdkmanager` should exist.
2. Append the following lines to `~/.profile`, so that other tools can locate your Android SDK installation. It is necessary to restart your terminal for these changes to take effect.
```
```bash
export PATH="$PATH:/opt/android-sdk/tools/bin"
export PATH="$PATH:/opt/android-sdk/platform-tools"
export ANDROID_HOME="/opt/android-sdk"
@@ -71,7 +71,7 @@ export ANDROID_HOME="/opt/android-sdk"
yes | sdkmanager --licenses
```
**Step 3: Download the source code**
### Step 3: Download the source code
To create a complete copy of the source code repository, navigate to your home directory and run:
```bash
@@ -79,13 +79,11 @@ git clone https://github.com/iSoron/uhabits.git
```
The repository will be downloaded to the directory `uhabits`.
**Step 4: Compile the source code**
### Step 4: Compile the source code
1. Navigate to the directory `uhabits`
2. Run `./gradlew assembleDebug --stacktrace`
If the compilation is successful, a debug APK will be generated somewhere inside the folder `uhabits-android/build/`. Currently, the full path is the following, but it may change in the future:
If the compilation is successful, a debug APK will be generated somewhere inside the folder `uhabits-android/build/`. Currently, the full path is `./uhabits-android/build/outputs/apk/debug/uhabits-android-debug.apk`, but it may change in the future.
./uhabits-android/build/outputs/apk/debug/uhabits-android-debug.apk
The APK can be installed using the tool `adb`, which should have been automatically installed at `/opt/android-sdk/platform-tools/adb` during compilation of the project.

View File

@@ -12,17 +12,6 @@
Please see `docs/BUILD.md` and `docs/TEST.md`
## Directory Layout
* `docs` Documentation for developers.
* `landing` Source code for our [landing page](http://loophabits.org/).
* `uhabits-android` Android-specific code.
* `uhabits-core` Common code used by all platforms (Android, iOS).
* `uhabits-core-legacy` Proof-of-concept module, developed to evaluate the feasibility of using Kotlin multiplatform for the app; not currently used, and it will be removed soon, once all useful code is ported to the other modules.
* `uhabits-ios` Experimental iOS port of Loop. Not currently used in production.
* `uhabits-server` Source code for any server-side components the app (for example, device sync).
* `uhabits-web` Experimental web port of Loop. Not currently used in production.
## Branching Policy
This repository uses the [git-flow branching model](https://nvie.com/posts/a-successful-git-branching-model/). Basically, there are two main branches, `dev` and `master`. All the development takes place in the `dev` branch. After the new features have been implemented and tested, they are merged into the `master` branch and a new version of the app is released. Please submit your pull requests against the `dev` branch.

View File

@@ -3,3 +3,9 @@ org.gradle.daemon=true
org.gradle.jvmargs=-Xms2048m -Xmx2048m
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
org.gradle.configureondemand=true
org.gradle.warning.mode=all
org.gradle.caching=true

102
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,102 @@
[versions]
agp = "8.9.2"
annotation = "1.9.1"
appcompat = "1.7.0"
appintro = "6.3.1"
commonsCodec = "1.16.0"
commonsIo = "1.3.2"
commonsLang3 = "3.14.0"
dagger = "2.55"
desugar = "2.1.4"
dexmaker = "2.28.3"
espresso = "3.6.1"
guava = "33.2.1-android"
hamcrest = "2.2"
jsr250 = "1.0"
jsr305 = "3.0.2"
junit = "1.2.1"
junitJupiter = "5.10.1"
junitVersion = "4.13.2"
konfetti-xml = "2.0.2"
kotlin = "2.1.10"
kotlinxCoroutinesCoreCommon = "1.3.8"
ksp = "2.1.10-1.0.30"
ktlint-plugin = "11.6.1"
ktor = "1.6.8"
ktxCoroutine = "1.10.1"
legacy-support = "1.0.0"
material = "1.12.0"
mockito-kotlin = "5.4.0"
opencsv = "5.9"
rules = "1.6.1"
shadow = "8.1.1"
sqliteJdbc = "3.45.1.0"
uiautomator = "2.3.0"
[libraries]
annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" }
appIntro = { group = "com.github.AppIntro", name = "AppIntro", version.ref = "appintro" }
appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
commons-codec = { module = "commons-codec:commons-codec", version.ref = "commonsCodec" }
commons-io = { module = "org.apache.commons:commons-io", version.ref = "commonsIo" }
commons-lang3 = { module = "org.apache.commons:commons-lang3", version.ref = "commonsLang3" }
dagger = { group = "com.google.dagger", name = "dagger", version.ref = "dagger" }
dagger-compiler = { group = "com.google.dagger", name = "dagger-compiler", version.ref = "dagger" }
desugar_jdk_libs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugar" }
dexmaker-mockito = { group = "com.linkedin.dexmaker", name = "dexmaker-mockito", version.ref = "dexmaker" }
espresso-contrib = { group = "androidx.test.espresso", name = "espresso-contrib", version.ref = "espresso" }
espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso" }
guava = { group = "com.google.guava", name = "guava", version.ref = "guava" }
hamcrest = { module = "org.hamcrest:hamcrest", version.ref = "hamcrest" }
jsr250-api = { group = "javax.annotation", name = "jsr250-api", version.ref = "jsr250" }
jsr305 = { group = "com.google.code.findbugs", name = "jsr305", version.ref = "jsr305" }
junit = { group = "androidx.test.ext", name = "junit", version.ref = "junit" }
junit-junit = { module = "junit:junit", version.ref = "junitVersion" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junitJupiter" }
konfetti-xml = { group = "nl.dionsegijn", name = "konfetti-xml", version.ref = "konfetti-xml" }
kotlin-stdlib-jdk8 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" }
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "ktxCoroutine" }
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "ktxCoroutine" }
kotlinx-coroutines-core-common = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core-common", version.ref = "kotlinxCoroutinesCoreCommon" }
kotlinx-coroutines-core-jvm = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm", version.ref = "ktxCoroutine" }
ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" }
ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
ktor-client-jackson = { group = "io.ktor", name = "ktor-client-jackson", version.ref = "ktor" }
ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktor" }
ktor-client-mock = { group = "io.ktor", name = "ktor-client-mock", version.ref = "ktor" }
ktor-jackson = { group = "io.ktor", name = "ktor-jackson", version.ref = "ktor" }
legacy-preference-v14 = { group = "androidx.legacy", name = "legacy-preference-v14", version.ref = "legacy-support" }
legacy-support-v4 = { group = "androidx.legacy", name = "legacy-support-v4", version.ref = "legacy-support" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin" }
opencsv = { group = "com.opencsv", name = "opencsv", version.ref = "opencsv" }
rules = { group = "androidx.test", name = "rules", version.ref = "rules" }
sqlite-jdbc = { module = "org.xerial:sqlite-jdbc", version.ref = "sqliteJdbc" }
uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "uiautomator" }
[bundles]
androidTest = [
"annotation",
"dagger",
"dexmaker-mockito",
"espresso-contrib",
"espresso-core",
"junit",
"ktor-client-mock",
"ktor-jackson",
"mockito-kotlin",
"rules",
"uiautomator"
]
test = [
"dagger",
"junit-junit",
"mockito-kotlin",
]
[plugins]
agp = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
ktlint-plugin = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint-plugin" }
shadow = { id = "com.github.johnrengelman.shadow", version.ref = "shadow" }

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -1,13 +1,32 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
}
resolutionStrategy.eachPlugin {
if (requested.id.id == "com.android.application") {
useModule("com.android.tools.build:gradle:${requested.version}")
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
}
}
include(":uhabits-android", ":uhabits-core", ":uhabits-server")
include(":uhabits-android", ":uhabits-core")
dependencyResolutionManagement {
@Suppress("UnstableApiUsage")
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
maven(url = "https://plugins.gradle.org/m2/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
maven(url = "https://jitpack.io")
}
}
include(":uhabits-android", ":uhabits-core")

View File

@@ -1,30 +0,0 @@
#!/bin/bash
input=$1
locale_name=$2
cat <<END
// --------------------------------------------------------------------------
// THIS FILE WAS AUTOMATICALLY GENERATED
//
// Please do not submit pull request to modify it. Corrections to translations
// may be submitted at https://translate.loophabits.org/
// --------------------------------------------------------------------------
package org.isoron.uhabits.i18n
END
prefix="override "
if [ "$locale_name" == "" ]; then
prefix="open "
echo "open class Strings() {"
else
echo "class Strings$locale_name : Strings() {"
fi
grep "<string name" "$1" | \
grep -v translatable | \
sed 's/&amp;/\&/g' | \
sed 's/^.*name="\([^"]*\)">\([^<]*\)<.*/ '"$prefix"'val \1 = "\2"/'
echo "}"

View File

@@ -1,46 +0,0 @@
#!/bin/bash
INPUT_DIR=../android/uhabits-android/src/main/res/
OUTPUT_DIR=../core/src/commonMain/kotlin/org/isoron/uhabits/i18n/
convert() {
./androidStringsToKt.sh $INPUT_DIR/$1/strings.xml "$2" > $OUTPUT_DIR/Strings$2.kt
}
#convert values ""
convert values-ar Arabic
convert values-bg Bulgarian
convert values-ca Catalan
convert values-cs Czech
convert values-da Danish
convert values-de German
convert values-el Greek
convert values-eo Esperanto
convert values-es Spanish
convert values-eu Basque
convert values-fa Persian
convert values-fi Finnish
convert values-fr French
convert values-hi Hindi
convert values-hr Croatian
convert values-hu Hungarian
convert values-in Indonesian
convert values-it Italian
convert values-iw Hebrew
convert values-ja Japanese
convert values-ko Korean
convert values-nl Dutch
convert values-no-rNO Norwegian
convert values-pl Polish
convert values-pt-rBR PortugueseBR
convert values-pt-rPT PortuguesePT
convert values-ro Romanian
convert values-ru Russian
convert values-sl Slovak
convert values-sr Serbian
convert values-sv Swedish
convert values-tr Turkish
convert values-uk Ukrainian
convert values-vi Vietnamese
convert values-zh-rCN ChineseCN
convert values-zh-rTW ChineseTW

View File

@@ -1,415 +1,536 @@
Name,Languages,"Translated (Words)","Target Words","Approved (Words)",Voted,"""+"" votes received","""-"" votes received","Winning (Words)",Joined
"Alinson Xavier (iSoron)","Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Polish; Arabic; German; Korean; Greek; Catalan; Bulgarian; Hindi; Slovenian; Ukrainian; Serbian (Cyrillic); Czech; Indonesian; Croatian; Danish; Dutch; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Norwegian; Afrikaans; Slovak; Armenian; Serbian (Latin); Uyghur",15497,18825,1308,0,1896,84,4315,"2016-03-05 18:35:27"
"Slobodan Simić (Слободан Симић) (slsimic)","Serbian (Latin); Serbian (Cyrillic)",2054,1831,2114,12,33,0,1991,"2021-02-03 14:26:07"
"Oglaigh Rystard (oglaignaheireann)","Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian",1103,1037,1327,1,13,6,954,"2017-03-31 09:13:19"
dukelc,Slovak,1046,993,0,0,0,0,0,"2020-08-27 14:02:41"
"David (Cliff122)",Swedish,1040,1019,725,6,0,0,700,"2020-01-21 13:56:55"
"Omer I.S. (omeritzics)",Hebrew,1040,927,1122,14,1,0,975,"2020-10-11 20:10:51"
"Alinson Xavier (iSoron)","Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Arabic; Polish; German; Korean; Bulgarian; Catalan; Greek; Slovenian; Hindi; Serbian (Cyrillic); Ukrainian; Czech; Danish; Dutch; Indonesian; Croatian; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Afrikaans; Norwegian; Armenian; Slovak; Serbian (Latin); Uyghur",15497,18825,1308,0,2094,111,4315,"2016-03-05 18:35:27"
"Slobodan Simić (Слободан Симић) (slsimic)","Serbian (Latin); Serbian (Cyrillic)",2072,1852,2139,12,30,0,2015,"2021-02-03 14:26:07"
dukelc,Slovak,1107,1052,0,0,0,0,0,"2020-08-27 14:02:41"
"Oglaigh Rystard (oglaignaheireann)","Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian",1103,1037,1327,1,22,13,954,"2017-03-31 09:13:19"
Avalysion,Georgian,1057,895,0,0,0,0,0,"2023-06-30 20:05:15"
"Mathew TK (mathew2006)",Malayalam,1057,1885,0,0,0,0,0,"2023-12-16 01:57:49"
REMOVED_USER,Hebrew,1051,944,1122,14,1,0,954,"2020-10-11 20:10:51"
"David (Cliff122)",Swedish,1040,1019,725,6,37,0,700,"2020-01-21 13:56:55"
"Intan Ayunda (Intan_Ayunda)",Indonesian,818,811,985,0,0,0,729,"2020-10-14 07:51:58"
"Mihail Stefanov (MStefanov)",Bulgarian,755,794,3,0,2,0,2,"2017-03-31 16:09:02"
dusanstrgar,Slovenian,770,730,0,0,0,0,0,"2017-03-31 10:30:28"
"Mihail Stefanov (MStefanov)",Bulgarian,755,794,3,0,2,4,2,"2017-03-31 16:09:02"
Osoitz,Basque,751,683,0,9,0,0,3,"2018-01-23 14:07:47"
KMakoto,"Chinese Traditional",745,1146,949,0,0,0,745,"2019-10-22 04:19:52"
"Evren (evrenkiymaz)",Turkish,688,604,0,71,28,22,0,"2020-10-04 03:39:16"
andaryon,Czech,681,606,0,108,0,0,0,"2021-11-25 10:20:45"
Tomairuka,Japanese,709,1842,1033,43,12,0,585,"2020-12-12 12:14:22"
"Evren (evrenkiymaz)",Turkish,688,604,0,71,31,22,0,"2020-10-04 03:39:16"
andaryon,Czech,681,606,0,108,21,0,0,"2021-11-25 10:20:45"
"Antti Kallio (antti.kallio)",Finnish,668,539,0,5,0,0,0,"2021-07-03 05:54:44"
"David Nos (david.nos)","Catalan; Spanish",667,731,0,0,1,0,0,"2020-01-04 10:15:36"
androide74,Italian,662,681,0,2,0,0,0,"2020-02-06 15:46:28"
Osoitz,Basque,655,595,0,9,0,0,3,"2018-01-23 14:07:47"
"Dmitriy Bogdanov (di72nn)",Russian,643,589,1197,0,36,0,515,"2017-03-31 10:00:48"
Tomairuka,Japanese,633,1636,909,43,0,0,564,"2020-12-12 12:14:22"
reyhoon,Persian,624,759,0,1,3,1,0,"2020-10-01 18:17:23"
"Dmitriy Bogdanov (di72nn)",Russian,643,589,1197,0,50,0,515,"2017-03-31 10:00:48"
reyhoon,Persian,624,759,0,1,3,2,0,"2020-10-01 18:17:23"
"Saeed Esmaili (saaeed.es20)",Persian,586,795,0,5,4,0,0,"2020-11-26 15:41:15"
fabian.bouchal,German,548,527,0,6,0,3,72,"2020-01-07 06:43:37"
"Isti (eisti)",Hungarian,528,476,0,0,0,0,0,"2020-12-03 12:02:51"
boban77,Czech,509,461,0,2,29,0,0,"2020-04-30 13:18:24"
fabian.bouchal,German,548,527,0,6,4,5,72,"2020-01-07 06:43:37"
"Isti (eisti)",Hungarian,528,476,0,0,1,0,0,"2020-12-03 12:02:51"
Aravinth_Earth,Tamil,511,961,0,12,0,0,0,"2024-02-23 12:37:28"
boban77,Czech,509,461,0,2,45,0,0,"2020-04-30 13:18:24"
"Martim Parente (martimparente)",Portuguese,505,542,0,38,0,0,0,"2020-08-26 10:22:11"
"Yoav Argov (YoavArgov)",Hebrew,501,461,0,0,1,8,91,"2017-04-28 07:23:01"
REMOVED_USER,Norwegian,501,498,501,0,148,0,501,"2017-07-05 19:02:25"
"chrrris1987 (Chrrris1987)",Dutch,467,478,0,23,0,0,0,"2020-02-03 05:26:04"
"黄克 (hk13127)","Chinese Simplified",461,765,0,1,0,0,24,"2020-01-17 23:16:03"
"黄克 (hk13127)","Chinese Simplified",461,765,0,1,0,0,22,"2020-01-17 23:16:03"
"Huy Ngo (huyngo)",Vietnamese,461,695,0,1,0,0,0,"2020-01-26 11:58:36"
"Arkadiusz Bubak (epitek)",Polish,458,416,52,24,9,4,0,"2020-11-05 05:11:58"
"Arkadiusz Bubak (epitek)",Polish,458,416,52,24,15,4,0,"2020-11-05 05:11:58"
"Radek Kuklík (kuklik.radek)",Czech,453,392,0,100,0,0,0,"2022-10-08 10:04:24"
marco.baturan,Esperanto,452,452,0,0,0,0,0,"2020-06-23 02:49:46"
"Sief Tarek (sieftarek135)",Arabic,447,455,0,0,0,0,0,"2021-02-07 14:35:21"
"Alparslan Şakçi (sakci)",Turkish,436,372,0,118,1,0,0,"2022-01-14 12:03:11"
JY3,"Chinese Simplified",427,727,295,0,1,0,222,"2021-03-08 08:53:35"
"Sief Tarek (sieftarek135)",Arabic,447,455,0,0,1,4,0,"2021-02-07 14:35:21"
"Alparslan Şakçi (sakci)",Turkish,436,372,0,118,2,0,0,"2022-01-14 12:03:11"
JY3,"Chinese Simplified",432,741,298,0,2,0,227,"2021-03-08 08:53:35"
"Samuel Guay (SamGuay)",French,426,486,0,6,0,0,0,"2020-06-25 07:14:38"
"Diana Karaseva (Sun_Dianka)",Russian,399,373,0,10,1,0,209,"2020-01-30 06:40:02"
"Alexander Jansson (dalecarlian)",Swedish,396,406,507,0,0,3,399,"2017-06-21 01:37:32"
"Alexander Jansson (dalecarlian)",Swedish,396,406,507,0,29,6,399,"2017-06-21 01:37:32"
luiandresgonzalez,Spanish,383,403,0,1,28,0,0,"2020-07-11 14:20:44"
"Thamara Andrade (tkcandrade)","Portuguese, Brazilian",380,387,0,0,1,0,239,"2020-01-09 19:35:48"
"Sølv Ræven (soelvraeven)",Danish,370,370,0,0,0,0,0,"2020-11-28 16:46:18"
strikeCunny2245,Icelandic,363,368,0,0,0,0,0,"2023-08-07 08:05:53"
"Anh Quân (dangquanuet)",Vietnamese,362,530,0,42,2,0,0,"2017-10-29 12:27:44"
"Alexander Haronitakis (kanakis)",Greek,349,372,0,0,0,0,0,"2023-09-13 04:10:43"
gapszi,Hungarian,348,301,0,86,0,0,0,"2019-04-08 01:35:54"
"Mahdi Nasiri (mahdi.nasiri)",Persian,343,465,0,39,3,1,0,"2017-07-14 09:17:25"
Seoyul,Korean,339,825,0,0,27,0,0,"2017-06-21 08:11:39"
"Magimai Prakasam (magimai)",Tamil,336,831,0,12,0,0,0,"2018-04-15 21:16:08"
"Michael Malak (MichaelKMalak)",Arabic,304,271,0,0,1,0,0,"2020-05-26 19:47:58"
Blinkin,Dutch,297,334,0,5,0,0,0,"2021-06-14 10:30:05"
"Magimai Prakasam (magimai)",Tamil,336,831,0,12,2,0,0,"2018-04-15 21:16:08"
"Star7 (Star7-crowdin)","Chinese Simplified",330,561,0,0,0,0,0,"2025-02-10 08:41:34"
Susanamesa,Spanish,306,342,0,11,0,0,0,"2023-01-01 23:56:35"
"Michael Malak (MichaelKMalak)",Arabic,304,271,0,0,4,2,0,"2020-05-26 19:47:58"
"Elina Salminen (salminen.elina.m)",Finnish,297,227,0,0,0,0,0,"2021-01-06 01:28:57"
ayane.m,Japanese,292,863,0,1,5,0,22,"2019-11-20 03:28:26"
"Marius Teufelweich (teufelweich)",German,267,272,611,4,13,1,146,"2021-03-12 04:11:38"
Blinkin,Dutch,297,334,0,5,1,0,0,"2021-06-14 10:30:05"
ayane.m,Japanese,292,863,0,1,8,0,23,"2019-11-20 03:28:26"
c.m,Greek,276,293,0,124,0,0,0,"2024-07-13 14:49:43"
"Marius Teufelweich (teufelweich)",German,267,272,611,4,23,3,146,"2021-03-12 04:11:38"
"Sumin Son (todaypp)",Korean,266,221,0,7,0,0,0,"2023-06-09 05:28:30"
hypnotichemionus,"Chinese Simplified",249,430,0,0,8,0,19,"2020-03-08 01:46:25"
"Israa Z (sosozozo)",Arabic,240,266,0,81,14,0,3,"2017-11-27 14:10:50"
cobalt59,German,237,234,0,1,24,1,132,"2017-06-05 05:18:33"
beriain,Basque,234,235,0,0,2,0,0,"2017-03-31 15:42:28"
pnhpnh,Vietnamese,225,343,0,1,3,0,0,"2017-11-27 12:06:07"
"Dika Fitrian Dwi Putra (OsamuDazai)",Indonesian,221,215,0,0,0,0,48,"2020-07-13 04:40:27"
easyrepro,Telugu,214,297,0,0,4,0,0,"2020-06-12 12:52:10"
taras-ko,Ukrainian,211,183,0,1,4,0,19,"2017-10-26 16:52:22"
"vinayak sharma (vinayak0504)",Hindi,211,456,0,0,0,0,0,"2023-05-18 18:31:51"
sojusnik,German,207,200,1,0,30,0,66,"2017-04-03 17:11:56"
"Andrij Mizyk (andmizyk)",Ukrainian,204,178,0,40,0,0,53,"2021-04-01 03:56:20"
"Andrij Mizyk (andm)",Ukrainian,204,178,0,40,1,0,53,"2021-04-01 03:56:20"
"Heru Yen (heruyen)",Indonesian,201,201,0,0,0,0,25,"2020-06-29 18:39:15"
"Vijaykumar Borkar (vjkumar)",Hindi,200,364,0,11,0,0,0,"2021-08-06 16:12:15"
_translator,French,199,227,0,11,0,0,0,"2021-07-06 07:54:12"
bearsdens,Romanian,198,210,0,0,0,0,0,"2022-08-28 17:08:33"
Ishmaeel,Turkish,193,174,0,129,17,6,0,"2017-10-04 03:54:00"
oscfd,Spanish,192,201,0,2,4,0,0,"2021-05-21 17:58:22"
REMOVED_USER,Spanish,192,201,0,2,5,0,0,"2021-05-21 17:58:22"
bruhwut,Vietnamese,189,292,0,1,0,0,0,"2021-05-21 07:16:30"
"Aputsiak Niels Janussen (aputtu)",Danish,187,200,0,0,0,0,0,"2019-08-28 05:47:42"
fbruna17,Danish,181,179,0,1,0,0,0,"2021-01-28 15:48:47"
Bryanx,Dutch,179,168,0,5,2,0,0,"2019-11-21 17:08:12"
"Omry Cohen (omrycohen)",Hebrew,175,156,0,1,0,0,33,"2021-01-18 07:33:23"
"Ivan Vlahov (vlahovivan)",Croatian,179,176,0,0,0,0,0,"2024-01-25 08:12:11"
"Omry Cohen (omrycohen)",Hebrew,175,156,0,1,0,0,12,"2021-01-18 07:33:23"
"Pierre GALIEGUE (pierre.galiegue)",French,171,194,0,24,4,0,0,"2020-08-16 11:41:35"
plitwin,Polish,168,151,0,2,31,0,49,"2021-01-20 06:18:37"
DionysosDV,Greek,165,153,0,0,0,0,0,"2021-02-27 19:05:25"
plitwin,Polish,168,151,0,2,55,0,49,"2021-01-20 06:18:37"
DionysosDV,Greek,165,153,0,0,27,4,0,"2021-02-27 19:05:25"
"Gustavo Lima (GustavoLima)",Portuguese,158,177,0,1,4,10,0,"2020-08-26 10:35:05"
"Alex V. (elvitalex)",Romanian,154,166,0,24,0,0,0,"2022-08-03 17:40:00"
"Ravi Rami (ramiravi)",Hindi,151,248,0,0,0,0,0,"2021-10-10 09:19:40"
"Lương Vĩnh Khang (LuongVinhKhang)",Vietnamese,144,256,0,0,46,1,0,"2017-08-10 10:05:58"
azzamsa,Indonesian,142,136,0,48,0,1,26,"2017-06-16 18:29:45"
"yoding (yodingc)","Chinese Traditional; Chinese Simplified",141,271,0,10,0,0,0,"2021-07-07 01:45:45"
"Neysa Nasywa (neysanasywa)",Indonesian,140,141,0,0,0,0,60,"2020-11-18 10:32:10"
mohmans,Arabic,139,141,0,12,1,0,0,"2020-11-23 02:48:00"
"Eilif Adelvice (adelvice)",Spanish,139,154,0,96,1,0,0,"2021-08-05 07:20:21"
"Mohammed Imthath (mimthath4)",Tamil,136,274,0,0,11,0,0,"2018-02-15 22:41:15"
mohmans,Arabic,139,141,0,12,7,1,0,"2020-11-23 02:48:00"
"Eilif Adelvice (adelvice)",Spanish,139,154,0,96,6,0,0,"2021-08-05 07:20:21"
"Mohammed Imthath (mimthath4)",Tamil,136,274,0,0,13,1,0,"2018-02-15 22:41:15"
carllacan,Catalan,134,155,0,2,0,0,0,"2021-11-13 13:12:07"
roptat,French,132,154,0,112,89,5,0,"2017-04-19 16:54:47"
"Trần Thái (tranhoangthai2001)",Vietnamese,127,186,0,8,1,0,0,"2018-03-01 10:51:39"
"OP Smosher (teenwolffan44)","Serbian (Cyrillic)",124,122,0,0,0,0,18,"2020-11-05 09:41:35"
"Tad Wohlrapp (TadWohlrapp)",German,124,122,0,0,2,0,0,"2022-06-28 04:55:41"
4001982248998,Esperanto,122,119,0,0,0,0,0,"2017-10-08 04:13:02"
"StoP4Me (Lcqp)",Romanian,121,119,0,0,3,0,0,"2018-05-06 18:51:59"
alalloush,Arabic,118,129,0,2,14,3,0,"2017-03-31 12:37:17"
"StoP4Me (Lcqp)",Romanian,121,119,0,0,6,0,0,"2018-05-06 18:51:59"
alalloush,Arabic,118,129,0,2,17,6,0,"2017-03-31 12:37:17"
"Brenda Correa (brenda.14)",Spanish,117,127,0,0,0,1,0,"2022-05-16 02:34:13"
Sebastian05067,Spanish,114,133,0,55,32,0,0,"2017-05-14 00:48:16"
"Tanya (MagicUnderHood)",Russian,114,98,0,19,0,0,54,"2019-04-21 10:44:03"
Sebastian05067,Spanish,114,133,0,55,28,0,0,"2017-05-14 00:48:16"
REMOVED_USER,Arabic,111,106,0,22,22,2,0,"2018-01-05 07:01:45"
"Iabin Arteaga (iabin)",Spanish,108,111,0,4,21,0,0,"2017-08-26 21:08:54"
REMOVED_USER,Arabic,111,106,0,22,23,3,0,"2018-01-05 07:01:45"
"Ivan Krušlin (krux3r)",Croatian,108,122,503,0,0,0,108,"2017-03-31 09:15:24"
2kaafone,Finnish,105,90,0,0,0,0,0,"2019-08-12 06:58:48"
"Iabin Arteaga (iabin)",Spanish,108,111,0,4,21,1,0,"2017-08-26 21:08:54"
REMOVED_USER,Finnish,105,90,0,0,0,0,0,"2019-08-12 06:58:48"
"Adam Jurkiewicz (hasztagg)",Polish,104,105,529,0,0,0,104,"2017-03-31 09:50:51"
"PILHA PARK (pilhaha)",Korean,101,88,0,0,0,0,0,"2023-06-30 23:51:41"
"just a name bro (justanamebr0)",Danish,98,109,0,0,1,0,0,"2019-06-19 11:57:55"
"Nam Nguyen (namnl2706)",Vietnamese,95,137,0,0,0,0,0,"2020-08-18 23:02:33"
"손유정 (yuwon1213)",Korean,95,57,0,0,1,0,0,"2021-03-30 05:25:33"
"손유정 (yuwon1213)",Korean,95,57,0,0,1,3,0,"2021-03-30 05:25:33"
ranmagen,Hebrew,91,78,0,0,0,0,0,"2021-02-16 05:44:31"
LoneWanderer,"Chinese Traditional",90,137,0,4,0,0,0,"2020-09-29 05:24:48"
ikkaz,Indonesian,89,84,0,5,0,0,4,"2019-09-02 19:58:54"
"Vo - (voyl)","Chinese Traditional",89,126,0,0,5,0,0,"2020-09-02 23:34:42"
"Irene K (Heaun)",Korean,88,75,0,25,0,0,0,"2020-03-16 11:31:12"
"Irene K (Heaun)",Korean,88,75,0,25,2,0,0,"2020-03-16 11:31:12"
Prosta4ok_ua,Ukrainian,87,84,0,1,0,0,17,"2020-01-23 19:43:41"
"Kumar Anand (kumar0500)",Hindi,87,125,0,0,0,0,0,"2020-11-07 02:46:09"
G.kio,Russian,87,82,0,0,1,0,0,"2023-08-24 19:43:00"
"Ohad Edri (ohadalte)",Hebrew,85,79,0,0,1,3,13,"2020-07-04 03:42:09"
helectron,Persian,84,102,0,1,0,0,0,"2021-03-02 04:10:51"
"Radu Cebotari (wildProgrammer)",Romanian,84,92,0,1,0,0,0,"2020-02-05 01:20:00"
"Bruces Lee (aplusbdesign)",Korean,82,66,0,0,0,0,0,"2021-08-23 11:27:18"
"Israa Z (sosozozo)",Arabic,79,87,0,43,14,0,3,"2017-11-27 14:10:50"
"Sofia Neves (sofiasonev)","Portuguese, Brazilian",79,84,0,1,0,0,46,"2020-03-12 18:19:46"
"Jacob Roller (jdr28070)",Korean,79,61,0,0,1,0,0,"2020-01-03 11:36:40"
"Radu Cebotari (wildProgrammer)",Romanian,84,92,0,1,1,0,0,"2020-02-05 01:20:00"
helectron,Persian,84,102,0,1,1,0,0,"2021-03-02 04:10:51"
"Bruces Lee (aplusbdesign)",Korean,82,66,0,0,2,0,0,"2021-08-23 11:27:18"
Tiralka,French,79,91,0,92,1,0,0,"2018-02-09 18:39:01"
"Jacob Roller (jdr28070)",Korean,79,61,0,0,1,1,0,"2020-01-03 11:36:40"
"Sofia Neves (sofiasonev)","Portuguese, Brazilian",79,84,0,1,0,0,46,"2020-03-12 18:19:46"
"Toni Mustonen (toni.mustonen)",Finnish,78,72,0,0,5,0,0,"2017-09-02 05:34:12"
"Michael (quelbs)",German,76,75,0,1,0,0,39,"2020-08-18 07:39:26"
"Fauz Aladeem (topfauz)",Arabic,76,77,0,0,0,1,0,"2020-02-21 22:46:12"
"Radoslaw Biernacki (radoslaw.biernacki)",Polish,70,74,0,56,1,0,1,"2020-12-15 17:55:31"
"Oliver Gronowski (OliverGronowski)",German,70,69,0,5,2,0,0,"2021-05-14 16:37:10"
"Michael (quelbs)",German,76,75,0,1,0,0,39,"2020-08-18 07:39:26"
"Anna Maria Stålberg (stalberg.annamaria)",Swedish,76,77,0,111,4,0,0,"2023-01-16 04:08:25"
"Radoslaw Biernacki (radoslaw.biernacki)",Polish,70,74,0,56,5,0,1,"2020-12-15 17:55:31"
"Oliver Gronowski (OliverGronowski)",German,70,69,0,5,3,0,0,"2021-05-14 16:37:10"
mimizuk,Japanese,68,193,0,0,2,1,39,"2022-05-18 10:10:38"
Ryeore,Polish,68,61,0,66,0,0,0,"2022-07-27 12:22:33"
RealDonald,Dutch,67,69,0,121,10,0,0,"2017-06-23 20:10:12"
"Dpd Eng (dpdeng)",Korean,67,48,0,0,1,0,0,"2022-10-15 10:56:44"
sirekanyan,"Armenian; Russian",66,65,0,0,0,0,0,"2020-04-18 11:32:52"
"Константин К. (kocyak1991)",Russian,64,60,0,0,1,2,0,"2018-06-10 13:39:37"
yukitsubaki,Japanese,64,185,0,32,0,0,36,"2020-01-01 13:17:44"
Suuis,Hindi,64,110,0,0,0,0,0,"2023-07-02 11:50:22"
"Laura Sophie (laurasophie20)",German,62,67,0,4,0,0,0,"2018-01-06 14:21:24"
raden20,Indonesian,61,62,177,0,1,0,64,"2017-04-09 22:04:23"
"Peter Williams (williamspete001)",Japanese,60,173,0,2,0,0,3,"2020-01-01 13:17:44"
"y (veggente)",Korean,61,56,0,0,0,1,0,"2022-06-28 10:41:18"
"Jan Wojtecki (j4nw)",Polish,58,46,0,0,0,0,26,"2017-11-02 05:42:14"
"Deepak Bharathi (deepakbharathi1994)",Tamil,56,107,0,0,11,4,0,"2017-09-17 08:00:31"
"Deepak Bharathi (deepakbharathi1994)",Tamil,56,107,0,0,13,4,0,"2017-09-17 08:00:31"
"Андрій Козицький (andriikozytskyi1108)",Ukrainian,52,52,0,0,1,0,0,"2018-10-22 01:45:08"
"Nil riera (nilriera2000)",Catalan,52,61,0,1,2,0,0,"2021-06-22 16:37:44"
"Neoone (Neooneqq)",Romanian,51,54,0,0,0,0,0,"2022-05-05 20:42:11"
REMOVED_USER,Italian,51,52,0,2,0,0,0,"2017-08-21 05:15:31"
govindap,"Japanese; Hindi",51,114,0,6,1,0,0,"2020-06-02 20:15:52"
govindap,"Japanese; Hindi",51,114,0,6,3,1,0,"2020-06-02 20:15:52"
"Neoone (Neooneqq)",Romanian,51,54,0,0,0,0,0,"2022-05-05 20:42:11"
"Mare Geldenhuys (mare.geldenhuys)",Afrikaans,50,57,0,0,0,0,0,"2017-10-20 18:00:14"
"Mahmoud Magdy (M7moudManson)",Arabic,49,60,0,6,8,1,0,"2021-08-21 09:01:38"
"Behnood HRazy (behnoodhr)",Persian,49,70,0,0,0,0,0,"2017-11-25 10:57:21"
"Mahmoud Magdy (M7moudManson)",Arabic,49,60,0,6,12,6,0,"2021-08-21 09:01:38"
J3ll3nl,Dutch,48,48,0,0,17,1,3,"2017-03-31 11:56:09"
"tat bz (Tat_i)",German,48,56,0,55,0,1,27,"2021-03-26 05:12:54"
vach,Armenian,47,36,0,0,0,0,0,"2020-04-18 16:53:12"
"Andrew Firnes (Anechan)",Russian,47,47,0,3,0,0,29,"2019-09-18 09:51:59"
andowero,Czech,47,38,0,0,3,0,0,"2020-01-20 02:29:01"
andowero,Czech,47,38,0,0,8,0,0,"2020-01-20 02:29:01"
vach,Armenian,47,36,0,0,0,0,0,"2020-04-18 16:53:12"
"Rahul Shishodia (rahul.shishodia.10)",Hindi,46,85,0,6,5,1,0,"2018-12-24 22:18:19"
"Coni Ragni (coni2ragnii)",Spanish,46,46,0,0,0,0,0,"2021-02-28 20:18:37"
Cp0204,"Chinese Simplified",45,72,0,0,0,0,0,"2019-08-20 11:04:27"
"cc (cavaz)",Italian,44,41,0,0,0,0,0,"2017-04-01 04:21:08"
"Boban Jagertraum (boban40)",Czech,43,38,0,2,18,1,0,"2017-03-31 09:39:16"
"Kamil Dziadek (prso94)",Polish,43,39,0,0,6,0,0,"2020-04-06 17:12:06"
"Andrej Šutovský (16andrej.s)",Slovak,44,41,0,0,0,0,0,"2022-06-12 18:01:16"
"Boban Jagertraum (boban40)",Czech,43,38,0,2,31,1,0,"2017-03-31 09:39:16"
"Kamil Dziadek (prso94)",Polish,43,39,0,0,11,0,0,"2020-04-06 17:12:06"
"Balázs Keresztury (belidzs)",Hungarian,42,41,501,0,7,0,38,"2017-04-06 02:40:24"
andreea.muscalagiu,Romanian,42,52,0,1,0,0,0,"2017-10-22 07:19:49"
"Me Me (gentelwom)",Arabic,42,40,0,0,0,0,0,"2020-11-08 20:44:01"
"Balázs Keresztury (belidzs)",Hungarian,42,41,501,0,7,0,38,"2017-04-06 02:40:24"
"Mateusz Duda (MateuszDuda)",Polish,42,42,0,0,6,0,0,"2021-08-17 11:27:11"
"Ali Elsheikh (aelsheikh1987)",Arabic,42,41,0,0,0,0,0,"2021-06-16 10:17:26"
"Ali Zali (stm19951995)",Persian,40,60,0,0,0,0,0,"2020-03-23 19:57:26"
"Mateusz Duda (MateuszDuda)",Polish,42,42,0,0,20,0,0,"2021-08-17 11:27:11"
"Mr Habti (donhabti)",Arabic,41,40,0,0,0,0,0,"2023-02-20 10:52:50"
"Sofia Veijonen (Suklaa) (sofia.veijonen)",Finnish,40,33,0,0,0,0,0,"2018-03-07 09:24:22"
dusanstrgar,Slovenian,39,41,0,0,0,0,0,"2017-03-31 10:30:28"
"Neeraj Verma (verma.neeraj.in)",Hindi,40,65,0,0,1,0,0,"2018-07-23 07:16:41"
"Ali Zali (stm19951995)",Persian,40,60,0,0,0,0,0,"2020-03-23 19:57:26"
"Limin Lu (liminlu)","Chinese Simplified",39,79,503,0,0,0,39,"2017-03-31 09:49:35"
Anshoe,Tamil,38,65,0,14,0,0,0,"2018-01-02 11:06:52"
Anshoe,Tamil,38,65,0,14,3,0,0,"2018-01-02 11:06:52"
"Pavel Protasov (pvphome)",Russian,38,33,0,0,0,0,0,"2024-02-09 03:40:33"
anasshm,Arabic,37,36,0,9,0,0,0,"2019-01-27 04:07:22"
hrexen,Armenian,37,37,0,0,0,0,0,"2020-12-09 02:30:34"
"Abdulrahman (D7M)",Arabic,36,39,0,0,0,0,0,"2020-01-29 18:55:30"
REMOVED_USER,Swedish,36,33,0,5,1,0,0,"2018-09-29 17:47:33"
xphsis,Basque,36,31,0,0,0,0,0,"2022-01-02 08:16:19"
REMOVED_USER,Swedish,36,33,0,5,2,0,0,"2018-09-29 17:47:33"
"Abdulrahman (D7M)",Arabic,36,39,0,0,4,0,0,"2020-01-29 18:55:30"
"Maria Chushnyakova (maria.ch)",Russian,36,31,0,3,0,0,0,"2021-08-17 03:23:58"
"長谷川知里 (chase0213)",Japanese,34,138,0,13,0,0,24,"2018-12-14 10:52:44"
"Piotr Łuczyński (peterluczynski)",Polish,33,30,0,6,10,0,2,"2020-01-29 07:27:40"
"Luis E. Perichon (luisperichon)",Spanish,33,40,0,104,0,0,0,"2017-09-04 13:46:06"
xphsis,Basque,36,31,0,0,0,0,0,"2022-01-02 08:16:19"
"長谷川知里 (chase0213)",Japanese,34,138,0,13,0,0,32,"2018-12-14 10:52:44"
"milad farahani (miladfarmahini90)",Persian,33,44,0,18,1,0,3,"2017-08-31 16:09:00"
"Luis E. Perichon (luisperichon)",Spanish,33,40,0,104,0,0,0,"2017-09-04 13:46:06"
"Piotr Łuczyński (peterluczynski)",Polish,33,30,0,6,17,0,2,"2020-01-29 07:27:40"
JoeLi,"Chinese Traditional",31,70,0,12,0,0,24,"2017-06-25 05:32:48"
andriikozytskyi2625,Ukrainian,31,23,0,0,0,0,0,"2019-07-08 00:16:41"
REMOVED_USER,Russian,31,30,0,2,4,0,3,"2018-12-03 23:55:47"
Moastafa,Arabic,31,25,0,0,0,0,0,"2020-07-06 11:37:53"
"hamza gamal (hamzagamal4444)",Arabic,31,28,0,0,0,0,0,"2020-08-03 15:23:34"
andriikozytskyi2625,Ukrainian,31,23,0,0,0,0,0,"2019-07-08 00:16:41"
Moastafa,Arabic,31,25,0,0,0,4,0,"2020-07-06 11:37:53"
"hamza gamal (hamzagamal4444)",Arabic,31,28,0,0,1,0,0,"2020-08-03 15:23:34"
yancyn,"Chinese Simplified",30,40,0,0,0,0,1,"2020-05-18 20:06:03"
"Siniša Sabljić (ssabljic)",Croatian,30,37,0,0,0,0,0,"2023-11-13 15:51:00"
"Ruud Schouten (ruudschouten)",Dutch,29,32,0,41,3,0,0,"2017-07-22 17:49:17"
"비니몬youtube (khj01025276475)",Korean,29,25,0,0,0,0,0,"2020-02-09 20:44:35"
"비니몬youtube (khj01025276475)",Korean,29,25,0,0,0,1,0,"2020-02-09 20:44:35"
avelneve,Indonesian,29,28,0,0,0,0,0,"2022-04-13 13:26:10"
bzhn,Ukrainian,29,26,0,0,4,0,0,"2022-06-18 17:09:13"
"Gergő Mihály (mihalygergo97)",Hungarian,28,69,0,0,0,0,0,"2024-02-13 08:35:57"
"Niraj Yadav (neverforgetniraj)",Hindi,26,48,0,0,0,0,0,"2017-04-11 02:26:50"
"Aaron Dalton (Perlkonig)",French,26,25,0,141,1,0,0,"2018-01-14 12:58:19"
"Jonny I (jonny99dj)",Italian,26,26,0,5,0,0,0,"2017-10-07 07:35:34"
"Guillaume Collic (gcollic)",French,26,28,0,126,11,0,0,"2017-05-05 16:13:00"
Pan_Filuta,Czech,25,21,0,5,8,0,3,"2017-04-29 12:55:14"
"Jonny I (jonny99dj)",Italian,26,26,0,5,0,0,0,"2017-10-07 07:35:34"
"Aaron Dalton (Perlkonig)",French,26,25,0,141,1,0,0,"2018-01-14 12:58:19"
Pan_Filuta,Czech,25,21,0,5,11,0,3,"2017-04-29 12:55:14"
"Eddie (eddieattaboy)","Chinese Traditional",25,34,0,1,0,0,0,"2020-11-04 21:48:05"
"eduard83 (barbany.eduard)",Catalan,24,25,0,2,0,0,0,"2019-06-26 14:59:47"
"A Aa (ylayzlmimashisafyoutub)",Arabic,23,33,0,34,1,1,0,"2021-09-27 15:34:26"
REMOVED_USER,Catalan,24,25,0,2,0,0,0,"2019-06-26 14:59:47"
"Caner Başaran (basarancaner)",Turkish,23,21,0,0,26,1,0,"2017-04-09 06:34:59"
"Ľuboš Čaky (lubos.caky)",Slovak,23,22,0,0,0,0,0,"2019-07-02 16:51:44"
"Neeraj Verma (verma.neeraj.in)",Hindi,22,37,0,0,1,0,0,"2018-07-23 07:16:41"
gnu-ewm,Polish,22,23,0,6,2,0,0,"2021-02-24 03:42:01"
"A Aa (ylayzlmimashisafyoutub)",Arabic,23,33,0,34,3,2,0,"2021-09-27 15:34:26"
hodanli,Turkish,22,26,0,0,1,0,0,"2017-11-03 14:33:41"
REMOVED_USER,Polish,22,23,0,6,9,0,0,"2021-02-24 03:42:01"
"Alcarkse (alexis.brusle)",French,21,25,0,7,11,0,0,"2017-08-06 09:32:29"
"Hugo Nogueira (hfrnogueira86)",Portuguese,21,22,0,0,0,0,0,"2023-01-09 22:51:24"
"Shashwat (goforgold)",Hindi,20,33,0,0,0,0,0,"2020-05-17 10:34:42"
olbotta,Italian,20,25,0,2,0,0,0,"2021-06-06 04:22:55"
can13,Turkish,19,14,0,8,0,0,0,"2021-01-03 10:39:03"
"사자솥 (toke1597)",Korean,19,19,0,0,0,0,0,"2020-02-04 13:36:11"
KenKailer,Arabic,19,25,0,0,0,0,0,"2022-05-10 06:16:54"
"İsa Eş (IsaEs)",Turkish,19,17,0,0,6,2,0,"2017-06-20 07:30:22"
"Magdalena Urbańczyk (madziia139)",Polish,19,19,0,0,0,0,0,"2017-10-21 03:01:04"
sheeCesu,French,19,18,0,48,4,0,0,"2017-12-21 17:01:39"
"사자솥 (toke1597)",Korean,19,19,0,0,0,0,0,"2020-02-04 13:36:11"
can13,Turkish,19,14,0,8,0,0,0,"2021-01-03 10:39:03"
KenKailer,Arabic,19,25,0,0,0,0,0,"2022-05-10 06:16:54"
axikman11111,Uyghur,18,19,0,0,0,0,0,"2018-10-13 12:25:31"
Adeline31,French,17,20,0,3,0,0,0,"2019-12-06 00:00:11"
"Hoon Jung (hooni100)",Korean,17,10,0,0,0,0,0,"2021-01-03 02:26:54"
takoyakibento,Korean,17,13,0,3,0,0,0,"2020-08-01 08:44:15"
"Sanjay Krishna (sjaykh)",Malayalam,18,42,0,0,0,0,0,"2024-06-01 08:57:37"
"Chuang-Chen Chiu (peterChiu9952)","Chinese Traditional",18,28,0,0,0,0,0,"2024-07-02 09:36:59"
AlexanderS,German,18,16,0,8,0,0,0,"2025-02-02 16:58:09"
"Ceara Lopez (cealopez)",Spanish,17,18,0,0,5,1,0,"2017-08-22 22:56:13"
bretzel15,German,16,20,0,0,0,0,0,"2020-04-06 02:49:14"
DebatablySane,Bulgarian,16,15,0,48,0,0,0,"2017-07-10 15:13:18"
Adeline31,French,17,20,0,3,1,0,0,"2019-12-06 00:00:11"
takoyakibento,Korean,17,13,0,3,0,0,0,"2020-08-01 08:44:15"
"Hoon Jung (hooni100)",Korean,17,10,0,0,0,0,0,"2021-01-03 02:26:54"
Annelotte,Dutch,17,20,0,0,0,0,0,"2022-11-09 08:33:20"
wppoqqqi,Korean,17,18,0,4,0,0,0,"2024-11-30 04:22:21"
"Şamil Ateşoğlu (m.samilatesoglu)",Turkish,16,22,0,11,6,3,0,"2017-07-05 18:37:08"
DebatablySane,Bulgarian,16,15,0,48,0,0,0,"2017-07-10 15:13:18"
bretzel15,German,16,20,0,0,1,0,0,"2020-04-06 02:49:14"
engineeringforgood,Russian,16,15,0,0,0,0,16,"2021-01-22 03:32:35"
"M7md Salahaddin (m7mdsalahaddin)",Arabic,16,16,0,1,0,0,0,"2024-07-17 18:49:07"
"Bhava Tharini (bhavidanush)",Tamil,15,37,0,0,0,0,0,"2019-10-09 05:43:11"
"Maro Chr (caprisunglasses)",Greek,14,17,0,0,0,0,0,"2021-08-17 06:53:33"
"Zeynep Esen (nezihaesen50)",Turkish,14,13,0,0,0,0,0,"2020-01-28 07:05:15"
"Ch. (sftblw)",Korean,15,17,0,1,0,0,0,"2023-01-25 19:22:34"
iamsurajbobade,Hindi,14,30,0,0,0,0,0,"2018-05-21 11:23:27"
"Faiz Ahamed (faiznewton)",Tamil,14,31,0,0,0,0,0,"2021-05-06 23:06:46"
"Zeynep Esen (nezihaesen50)",Turkish,14,13,0,0,0,0,0,"2020-01-28 07:05:15"
"Sanji Vinsmock (mukanzhanbolat4)",Russian,14,14,0,0,0,0,0,"2020-02-18 12:38:54"
"Zeeshan Rabbani (Zeera)",Hindi,14,25,0,0,0,0,0,"2020-09-15 11:32:01"
"pi hobbes (uwe_silv)",Japanese,14,46,0,0,0,0,0,"2022-01-15 02:57:14"
"Anastasia Borchuk (al2.borchuk)",Russian,14,14,0,0,0,0,0,"2020-04-14 13:22:49"
"Fikret Bilici (fikretbilici)",Turkish,14,13,0,0,0,0,0,"2020-06-21 17:16:11"
"EuiHo Hwang (euiho.hwang)",Korean,14,16,0,0,0,0,0,"2020-06-23 02:40:01"
"Uwe Mönks (schirinowski)",German,13,12,0,0,0,0,0,"2021-02-18 04:00:41"
"Dave (xdave)",Hungarian,13,11,0,0,0,0,0,"2020-03-02 20:56:50"
"Ana Kelly Vale (anakvale)","Portuguese, Brazilian",13,21,0,4,0,0,2,"2022-03-30 00:15:37"
GiorgioHerbie,Italian,13,15,0,0,0,0,0,"2022-01-17 17:35:40"
"EuiHo Hwang (euiho.hwang)",Korean,14,16,0,0,1,0,0,"2020-06-23 02:40:01"
"Zeeshan Rabbani (Zeera)",Hindi,14,25,0,0,0,0,0,"2020-09-15 11:32:01"
"Faiz Ahamed (faiznewton)",Tamil,14,31,0,0,0,0,0,"2021-05-06 23:06:46"
"Maro Chr (caprisunglasses)",Greek,14,17,0,0,0,0,0,"2021-08-17 06:53:33"
"pi hobbes (uwe_silv)",Japanese,14,46,0,0,0,0,14,"2022-01-15 02:57:14"
"Mar Tous (mtousfernandez)",Catalan,14,18,0,0,0,0,0,"2022-08-16 17:55:28"
Ferhatt,Turkish,14,13,0,3,0,0,0,"2022-12-13 12:52:20"
alchemiker,German,14,13,0,0,0,0,0,"2024-09-03 10:16:04"
"Nenad Vukotic (vukotic.nenad)","Serbian (Cyrillic)",13,13,0,1,2,6,0,"2019-01-31 14:29:15"
soura2,Arabic,12,13,0,0,0,0,0,"2020-01-13 19:23:47"
"Dave (xdave)",Hungarian,13,11,0,0,0,0,0,"2020-03-02 20:56:50"
"Uwe Mönks (schirinowski)",German,13,12,0,0,0,0,0,"2021-02-18 04:00:41"
Herbie_23,Italian,13,15,0,0,0,0,0,"2022-01-17 17:35:40"
"Ana Kelly Vale (anakvale)","Portuguese, Brazilian",13,21,0,4,0,0,2,"2022-03-30 00:15:37"
"Minsu (cknblue)",Korean,13,10,0,1,0,0,0,"2022-05-18 00:26:54"
"shreyas (techiespace)",Hindi,12,20,0,0,0,0,0,"2018-06-10 01:14:26"
soura2,Arabic,12,13,0,0,0,0,0,"2020-01-13 19:23:47"
"Ammar Naif (Ammar_Naif)",Arabic,12,12,0,6,0,0,0,"2022-01-15 05:16:41"
"Jo Chuang (josephch405)","Chinese Traditional",11,24,0,0,0,0,11,"2017-06-16 20:21:06"
Vmrc,French,11,12,0,2,0,0,0,"2020-11-02 05:35:06"
"Ammar Naif (Ammar_Naif)",Arabic,11,11,0,4,0,0,0,"2022-01-15 05:16:41"
"Sonu Sharma (riteetude)",Hindi,11,23,0,0,0,0,0,"2021-05-30 19:38:00"
"Lucas Depetris (lucasdepetrisd)","Spanish; Catalan; Italian; French",11,12,0,12,0,0,0,"2023-10-24 21:16:21"
"Mihael Wagner (miha.wagner)",Slovenian,10,9,0,7,0,0,0,"2017-10-18 18:26:29"
"Anonymous edgy nerd (yamentaad)",Arabic,10,13,0,1,0,0,0,"2018-05-06 09:23:57"
"Edwin van Rooij (edwinvrooij)",Dutch,10,13,0,17,0,0,0,"2018-11-05 03:59:10"
"Brian Camacho (bmcamacho)",Polish,10,11,0,0,1,1,0,"2020-08-03 02:27:28"
"Mihael Wagner (miha.wagner)",Slovenian,10,9,0,7,0,0,0,"2017-10-18 18:26:29"
"Hrant Hakobian (hrastgh1)",Armenian,10,9,0,0,0,0,0,"2021-08-29 15:22:10"
"sathvic k (sathvictripleseven)",Telugu,10,17,0,0,0,0,0,"2020-09-11 08:11:32"
"Ahmed Mosaad (ahmed.mosaad2018)",Arabic,10,12,0,6,0,0,0,"2021-02-03 18:45:43"
"Anonymous edgy nerd (yamentaad)",Arabic,10,13,0,1,0,0,0,"2018-05-06 09:23:57"
"Hrant Hakobian (hrastgh1)",Armenian,10,9,0,0,0,0,0,"2021-08-29 15:22:10"
"Milan Siebenbürger (lennyd)",Czech,10,7,0,1,1,0,0,"2022-01-30 07:09:42"
"Zesar Cebrián (Txorrota)",Spanish,10,44,0,0,0,0,0,"2022-02-09 01:34:32"
"Milan Siebenbürger (lennyd)",Czech,10,7,0,1,0,0,0,"2022-01-30 07:09:42"
"Suhaili Hassan (kucingsyg96)",Indonesian,9,10,0,0,0,0,0,"2018-06-10 11:55:09"
"Слави Велчев (BRO36S) (gg13656)",Bulgarian,10,11,0,9,0,0,0,"2025-01-09 08:47:04"
"Sourire Lucide (sourire_lucide)",Russian,9,10,0,0,1,0,0,"2018-03-22 01:37:55"
"Martin Vostatek (martinvostatek)",Czech,9,8,0,32,2,0,0,"2019-01-21 13:52:36"
"Seweryn Piotrowski (Draxxsx)",Polish,9,10,0,0,19,0,0,"2020-01-02 09:55:48"
"Jakob Weickmann (jweickm)",Japanese,8,21,0,0,0,0,0,"2021-10-05 11:10:25"
"Suhaili Hassan (kucingsyg96)",Indonesian,9,10,0,0,0,0,0,"2018-06-10 11:55:09"
"Martin Vostatek (martinvostatek)",Czech,9,8,0,32,3,0,0,"2019-01-21 13:52:36"
"Seweryn Piotrowski (Draxxsx)",Polish,9,10,0,0,26,0,0,"2020-01-02 09:55:48"
omoise,French,9,11,0,1,0,0,0,"2023-12-26 14:27:17"
Rex123,Persian,8,8,0,0,0,0,0,"2017-07-01 00:47:42"
"Jakob Weickmann (jweickm)",Japanese,8,21,0,0,0,0,8,"2021-10-05 11:10:25"
"Andrey ZaXeLoN (waragaa)",Russian,7,7,0,8,1,0,0,"2017-09-18 21:37:42"
"Konstantin (KZhidovinov)",Russian,7,7,0,0,0,0,0,"2020-01-29 13:35:12"
ftfoi,Norwegian,7,6,0,0,0,0,0,"2020-04-11 20:42:35"
"Vladimir Pavlychev (vovs03)",Russian,7,9,0,0,0,0,0,"2017-12-18 02:46:56"
"Felipe Chagas (chagretes)","Portuguese, Brazilian",7,8,0,0,3,0,5,"2022-01-10 12:20:25"
"Konstantin (KZhidovinov)",Russian,7,7,0,0,0,0,0,"2020-01-29 13:35:12"
pkorove,Greek,7,7,0,0,1,0,0,"2020-03-07 11:36:12"
ftfoi,Norwegian,7,6,0,0,0,0,0,"2020-04-11 20:42:35"
"Андрій Козицький (andriikozytskyi3807)",Ukrainian,7,12,0,2,0,0,0,"2020-09-26 20:31:56"
pkorove,Greek,7,7,0,0,0,0,0,"2020-03-07 11:36:12"
ChloeLiang,Japanese,6,22,0,0,1,0,3,"2017-08-08 05:02:59"
"Felipe Chagas (chagretes)","Portuguese, Brazilian",7,8,0,0,3,0,5,"2022-01-10 12:20:25"
"Tomáš Miklovič (zyppi)",Slovak,7,7,0,0,0,0,0,"2022-09-11 15:12:06"
"Sam (SorodonSorodon)",German,6,6,0,13,0,0,0,"2017-04-14 11:09:27"
ChloeLiang,Japanese,6,22,0,0,1,0,3,"2017-08-08 05:02:59"
"닉닉 (seohu9466)",Korean,6,14,0,13,0,0,0,"2017-10-09 23:08:15"
"Sarita Cajas (sarayanacajas)",Spanish,6,4,0,0,1,0,0,"2021-05-14 14:27:59"
erfan2927,Persian,6,6,0,0,0,0,0,"2018-04-09 02:12:44"
"Burak Ceylan (7burakceylan)",Turkish,6,6,0,0,0,0,0,"2018-05-20 17:24:19"
andriikozytskyi2018,Ukrainian,5,5,0,0,0,0,0,"2017-09-03 05:24:43"
"Vitor Henrique (vitorhcl)","Portuguese, Brazilian",5,8,0,1,0,0,0,"2022-03-08 20:00:59"
"Sarita Cajas (sarayanacajas)",Spanish,6,4,0,0,1,0,0,"2021-05-14 14:27:59"
"خالد (mkhrafi1999)",Arabic,6,3,0,6,0,0,0,"2023-06-25 00:36:13"
"Matthias Joly (joly.matt12)",French,5,8,0,27,1,0,0,"2017-08-28 09:53:59"
"Tomáš Hrabáček (Hrabyyy)",Czech,5,3,0,0,1,0,0,"2021-05-27 11:58:11"
"Guerra Ivaneth (rossanaiva-04)",Spanish,5,7,0,0,0,0,0,"2019-02-03 16:48:59"
andriikozytskyi2018,Ukrainian,5,5,0,0,0,0,0,"2017-09-03 05:24:43"
"Дмитрий Хапенков (d.khapenkov)",Russian,5,5,0,6,4,0,2,"2018-01-06 23:00:43"
"Guerra Ivaneth (rossanaiva-04)",Spanish,5,7,0,0,0,0,0,"2019-02-03 16:48:59"
"Micaela Pighin (micaelapiighin)",Spanish,5,6,0,1,0,0,0,"2019-10-09 23:32:42"
"Manuel Tassi (Mannivu)",Italian,5,6,0,0,0,0,0,"2021-01-03 11:00:33"
"Neko123 (emandic11)","Serbian (Cyrillic)",4,4,0,57,0,0,0,"2021-04-21 15:33:29"
"Manuel (Mannivu)",Italian,5,6,0,0,0,0,0,"2021-01-03 11:00:33"
"Tomáš Hrabáček (Hrabyyy)",Czech,5,3,0,0,2,0,0,"2021-05-27 11:58:11"
"Vitor Henrique (vitorhcl)","Portuguese, Brazilian",5,8,0,1,0,0,0,"2022-03-08 20:00:59"
SubhamJena,Hindi,5,12,0,3,0,0,0,"2023-04-19 11:13:19"
"Lopo Isaac Fernández (rocapata)",Spanish,4,3,0,0,0,0,0,"2018-09-20 11:46:22"
"Eli Besirov (elibesirov07)",Turkish,4,4,0,0,0,0,0,"2019-03-25 07:12:34"
bziuum,Polish,4,4,0,0,6,0,0,"2020-09-01 09:08:01"
marmo,German,4,4,0,0,0,0,0,"2021-01-13 01:16:35"
bziuum,Polish,4,4,0,0,3,0,0,"2020-09-01 09:08:01"
"Craig Foobar (craig.foobar)",German,3,3,0,25,0,0,0,"2022-02-20 16:55:47"
Katarin,Ukrainian,3,3,0,0,0,0,0,"2022-03-17 14:44:59"
"Sarath S (CyberShark)",Tamil,3,7,0,0,0,0,0,"2020-08-27 22:43:16"
"Neko123 (emandic11)","Serbian (Cyrillic)",4,4,0,57,0,0,1,"2021-04-21 15:33:29"
"Mo Heydari (Mrheydari)",Dutch,4,4,0,0,0,0,0,"2023-02-21 04:54:49"
"Srekaravarshan N K (srekaravarshan)",Tamil,4,4,0,0,0,0,0,"2023-04-22 06:08:57"
"Thoum Ptrgnt (thomas.petrignet)",French,3,3,0,2,0,3,0,"2017-09-23 19:25:52"
carsten_kafke,German,3,3,0,43,0,0,3,"2017-10-27 13:27:47"
"Vagner Roberto (vagner.trompete)","Portuguese, Brazilian",3,3,0,0,0,0,0,"2017-12-30 17:54:26"
"Igor Piskun (i_piskun)",Ukrainian,3,3,0,0,0,0,0,"2018-01-19 15:20:27"
"Cláudio Bernardo (claudiobernardo.ti)","Portuguese, Brazilian",3,4,0,1,0,0,0,"2019-01-08 14:41:10"
"Unnie Here (Carb)",Hindi,3,8,0,0,0,0,0,"2020-03-18 23:34:35"
REMOVED_USER,"Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-11-18 09:02:37"
"Thoum Ptrgnt (thomas.petrignet)",French,3,3,0,2,0,3,0,"2017-09-23 19:25:52"
"Oleg Kogut (kogut_oleg)",Ukrainian,3,3,0,0,0,0,0,"2018-12-28 14:31:02"
carsten_kafke,German,3,3,0,43,0,0,3,"2017-10-27 13:27:47"
Magidxz,Arabic,3,3,0,0,0,0,0,"2021-01-05 05:02:54"
"Péter Bernát (bernatp)",Hungarian,3,2,0,0,0,0,0,"2019-11-30 15:50:33"
"joabe gabriel (joabegabrielcma1)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-21 09:08:59"
"Gabriel Cavalcante (gabrielc.alves14)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-06 22:24:54"
"Martin Zimdahl (zimdahlmartin)",Swedish,3,2,0,0,1,0,3,"2018-09-15 04:39:22"
atomjani,Hungarian,3,3,0,0,0,0,0,"2019-01-19 00:49:25"
"mohammadali barati (mabaraty)",Persian,3,3,0,0,0,0,0,"2021-07-10 05:54:44"
"Hiohana Rilary (hiohanarilary)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2019-07-31 20:42:20"
"Tejaswini Boppana (Tejaswini)",Telugu,3,1,0,0,0,0,0,"2021-08-27 23:48:55"
"Andrea Bianchi (andreawhite1597)",Italian,3,1,0,1,0,0,0,"2018-01-21 17:45:48"
"Ño Bí Tã (pt614553)",Arabic,2,8,0,1,0,2,0,"2021-05-22 20:41:01"
"Judith Ayala (Azul1612)",Spanish,2,1,0,0,0,1,0,"2021-05-18 17:07:19"
"Valerij D (vala.dobler)",German,2,2,0,0,0,0,0,"2018-09-22 09:38:27"
"Balthazar Aubard (Balatzar)",French,2,5,0,0,1,0,0,"2017-09-23 01:42:57"
"Ahmed Bazazo (ahmedbazazo)",Arabic,2,2,0,0,0,0,0,"2022-02-19 20:11:09"
"Ali Zaida (alizaeda92)",Arabic,2,2,0,0,0,0,0,"2019-12-01 11:47:00"
"FAy FAy (fayfayfay52)","Chinese Traditional",2,5,0,0,0,0,0,"2017-10-06 08:53:21"
Soroor_SI,Persian,2,2,0,0,0,0,0,"2018-06-10 06:28:27"
chavs1997,Russian,2,2,0,9,0,0,0,"2018-05-18 16:58:19"
"Naveen jai krishna (njsbpolymer1)",Tamil,2,5,0,0,0,0,0,"2020-01-10 14:19:41"
omerfarukbas,Turkish,2,3,0,19,2,0,0,"2017-08-14 16:10:35"
"Ilyas Fekhar (il47yas)",Arabic,2,2,0,0,0,0,0,"2018-04-17 22:00:41"
"Héctor Mañas García (hectodium)",Catalan,2,3,0,0,0,0,0,"2021-10-02 20:32:09"
"Walid Baazia (walidbaazia2005)",Arabic,2,1,0,0,0,0,0,"2021-01-27 12:47:34"
"fatemeh s (fargolseifoori3)",Persian,2,2,0,0,0,0,0,"2019-01-31 12:06:57"
"hesamiranii (esam.matouri)",Persian,2,2,0,0,0,0,0,"2018-09-22 16:33:36"
"Gabriel Cavalcante (gabrielc.alves14)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-06 22:24:54"
"joabe gabriel (joabegabrielcma1)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-08-21 09:08:59"
"Martin Zimdahl (zimdahlmartin)",Swedish,3,2,0,0,2,0,3,"2018-09-15 04:39:22"
REMOVED_USER,"Portuguese, Brazilian",3,4,0,0,0,0,0,"2018-11-18 09:02:37"
"Oleg Kogut (kogut_oleg)",Ukrainian,3,3,0,0,0,0,0,"2018-12-28 14:31:02"
"Cláudio Bernardo (claudiobernardo.ti)","Portuguese, Brazilian",3,4,0,1,0,0,0,"2019-01-08 14:41:10"
atomjani,Hungarian,3,3,0,0,0,0,0,"2019-01-19 00:49:25"
"Hiohana Rilary (hiohanarilary)","Portuguese, Brazilian",3,4,0,0,0,0,0,"2019-07-31 20:42:20"
"Péter Bernát (bernatp)",Hungarian,3,2,0,0,0,0,0,"2019-11-30 15:50:33"
"Unnie Here (Carb)",Hindi,3,8,0,0,0,0,0,"2020-03-18 23:34:35"
"Sarath S (CyberShark)",Tamil,3,7,0,0,0,0,0,"2020-08-27 22:43:16"
Magidxz,Arabic,3,3,0,0,0,0,0,"2021-01-05 05:02:54"
"mohammadali barati (mabaraty)",Persian,3,3,0,0,0,0,0,"2021-07-10 05:54:44"
"Tejaswini Boppana (Tejaswini)",Telugu,3,1,0,0,0,0,0,"2021-08-27 23:48:55"
"Craig Foobar (craig.foobar)",German,3,3,0,25,1,0,0,"2022-02-20 16:55:47"
Katarin,Ukrainian,3,3,0,0,0,0,0,"2022-03-17 14:44:59"
ayet,Arabic,3,3,0,0,0,0,0,"2023-08-16 20:18:12"
REMOVED_USER,Ukrainian,2,2,0,0,0,0,0,"2017-06-15 12:24:44"
"Alex Stein (diefaust1993)",Russian,2,2,0,4,4,0,2,"2017-07-13 06:56:17"
omerfarukbas,Turkish,2,3,0,19,2,0,0,"2017-08-14 16:10:35"
"Balthazar Aubard (Balatzar)",French,2,5,0,0,1,0,0,"2017-09-23 01:42:57"
"FAy FAy (fayfayfay52)","Chinese Traditional",2,5,0,0,0,0,0,"2017-10-06 08:53:21"
"Ilyas Fekhar (il47yas)",Arabic,2,2,0,0,0,0,0,"2018-04-17 22:00:41"
amei,"Portuguese, Brazilian",2,2,0,0,0,0,0,"2018-04-19 19:42:28"
"أم محمد تقي (souadboudia19)",Arabic,2,2,0,0,0,0,0,"2020-06-13 15:24:17"
LNDDYL,"Chinese Traditional",2,4,0,0,0,0,2,"2018-04-22 04:00:19"
"조화정 (yunjoo337)",Korean,2,2,0,0,0,0,0,"2019-06-16 22:25:31"
"Sidali Aymen (sidaliaymen950)",Arabic,2,2,0,0,0,0,0,"2022-01-31 18:50:59"
"Jimmy Young (Jimmyyoung)","Chinese Traditional",2,4,0,0,0,0,2,"2018-04-22 04:00:19"
chavs1997,Russian,2,2,0,9,0,0,0,"2018-05-18 16:58:19"
Soroor_SI,Persian,2,2,0,0,0,0,0,"2018-06-10 06:28:27"
"Valerij D (vala.dobler)",German,2,2,0,0,0,0,0,"2018-09-22 09:38:27"
"hesamiranii (esam.matouri)",Persian,2,2,0,0,0,0,0,"2018-09-22 16:33:36"
"fatemeh s (fargolseifoori3)",Persian,2,2,0,0,0,0,0,"2019-01-31 12:06:57"
"Danial Agh (danialagh)",Persian,2,3,0,0,0,0,0,"2019-03-30 13:24:16"
"조화정 (yunjoo337)",Korean,2,2,0,0,0,0,0,"2019-06-16 22:25:31"
"Ali Zaida (alizaeda92)",Arabic,2,2,0,0,0,0,0,"2019-12-01 11:47:00"
"Naveen jai krishna (njsbpolymer1)",Tamil,2,5,0,0,1,0,0,"2020-01-10 14:19:41"
"أم محمد تقي (souadboudia19)",Arabic,2,2,0,0,0,0,0,"2020-06-13 15:24:17"
"Walid Baazia (walidbaazia2005)",Arabic,2,1,0,0,0,0,0,"2021-01-27 12:47:34"
"Judith Ayala (Azul1612)",Spanish,2,1,0,0,0,1,0,"2021-05-18 17:07:19"
"Ño Bí Tã (pt614553)",Arabic,2,8,0,1,0,2,0,"2021-05-22 20:41:01"
"Héctor Mañas García (hectodium)",Catalan,2,3,0,0,0,0,0,"2021-10-02 20:32:09"
"Sidali Aymen (sidaliaymen950)",Arabic,2,2,0,0,0,0,0,"2022-01-31 18:50:59"
"Ahmed Bazazo (ahmedbazazo)",Arabic,2,2,0,0,0,0,0,"2022-02-19 20:11:09"
"HypemanKEK (rocasta.dodvi)",Russian,2,2,0,0,0,0,0,"2023-01-13 03:45:06"
"Gmas (gustmaes1)",Dutch,2,2,0,0,0,0,0,"2023-01-26 13:52:54"
"Катерина Ховалкина (katerina959)",Russian,2,2,0,1,0,0,0,"2023-05-18 14:50:30"
"Pratheba Devanathan (devprath05)",Tamil,2,2,0,0,1,0,0,"2023-06-05 12:35:45"
"Gordon James Campbell (gordonjamescampbell)",Catalan,2,2,0,0,0,0,0,"2023-06-23 23:23:46"
"Suren Airyanam (suren.airyanam)",Persian,2,2,0,0,0,0,0,"2023-10-21 18:01:41"
axq,German,2,1,0,1,0,0,0,"2024-02-29 17:14:13"
"Hades Mori (Hades_Mori)",Ukrainian,2,2,0,0,0,0,0,"2024-07-03 07:14:58"
iSoron2,"Portuguese, Brazilian",1,1,0,0,0,0,0,"2017-03-18 17:56:29"
"Anton (tT0NG)","Chinese Traditional",1,2,0,0,0,0,1,"2017-07-06 14:18:39"
"Luca Gori (grolcu)",Italian,1,2,0,0,0,0,0,"2020-09-26 23:26:15"
axd,Spanish,1,1,0,15,0,0,0,"2017-09-12 05:48:51"
REMOVED_USER,Russian,1,2,0,6,1,0,1,"2019-12-26 05:37:01"
jonesses,German,1,1,0,1,0,0,1,"2021-01-01 08:03:18"
"Alan Jeon (skyisle)",Korean,1,2,0,8,0,0,0,"2018-01-09 10:46:00"
"Maria Fefelova (mashafefel)",Russian,1,1,0,0,0,0,0,"2019-05-18 02:03:56"
"Patrick Pimenta (trickap1)","Portuguese, Brazilian",1,1,0,0,0,0,0,"2018-12-01 14:31:21"
"박찌 (perpact20)",Korean,1,1,0,0,0,0,0,"2018-02-10 10:11:44"
"Kan Black (kanblack.va)",Vietnamese,1,2,0,0,0,1,0,"2019-01-15 03:50:10"
"Anastasiia Bondarenko (nastasya.bondarenko.97)",Russian,1,1,0,0,0,0,0,"2019-06-07 17:43:08"
axd,Spanish,1,1,0,15,1,0,0,"2017-09-12 05:48:51"
"Wibi Cahyo (wbcahyoh)",Indonesian,1,3,0,0,0,0,0,"2017-12-14 06:35:58"
sanyoniket,,0,0,0,0,0,0,0,"2019-07-23 12:58:40"
"Sri Harsha Bhogi (sriharshabhogi)",,0,0,0,0,0,0,0,"2018-09-02 05:31:53"
Irsgram,Russian,0,0,0,1,0,0,0,"2019-09-30 16:42:20"
"Baran Özavcı (n2141n)",Turkish,0,0,0,1,0,0,0,"2022-02-26 04:32:51"
"Masataka Yakura (myakura)",Japanese,0,0,0,1,0,0,0,"2021-09-03 22:10:36"
ava_rfie,Persian,0,0,0,1,0,0,0,"2019-06-09 16:19:24"
T-v-Gerwen,Dutch,0,0,0,47,0,0,0,"2018-03-02 10:26:33"
"George Merkulov (george142.emarket)",Russian,0,0,0,11,0,0,0,"2019-06-09 19:47:02"
philfr49,French,0,0,0,2,0,0,0,"2018-09-03 14:20:32"
"عبد الناصر سعيد الثبيتي (asaeed)",,0,0,0,0,0,0,0,"2018-03-13 02:09:35"
"Thomas Orlita (Thomas995)",Czech,0,0,0,1,0,0,0,"2017-12-24 04:08:27"
"Edmunds Edmundam (edmundam)",,0,0,0,0,0,0,0,"2020-06-01 14:18:18"
"Elmo (oberknecht)",,0,0,0,0,0,0,0,"2020-04-16 08:45:50"
"Равиль Мифтахов (ravilmif47)",Russian,0,0,0,1,0,0,0,"2019-08-12 21:58:30"
"Manny Farsangy (manifarsangi)",Persian,0,0,0,12,0,0,0,"2021-08-10 05:32:28"
"Samuel Przeździęk (samek22)",Polish,0,0,0,1,0,0,0,"2021-08-01 00:49:01"
"Saiprasath B (Saiprasath)",,0,0,0,0,0,0,0,"2021-07-11 11:10:41"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-08-24 00:17:43"
REMOVED_USER,,0,0,0,0,0,0,0,"2020-02-01 03:47:48"
"Arjun K. (arjunkdot)",,0,0,0,0,0,0,0,"2020-09-20 11:16:18"
EwanB,,0,0,0,0,0,0,0,"2019-11-19 10:04:38"
shuvo786,,0,0,0,0,0,0,0,"2019-11-13 00:18:12"
"Pro AAA (pro1010)",Arabic,0,0,0,1,0,0,0,"2022-02-14 03:32:44"
" (manuL96)",,0,0,0,0,0,0,0,"2022-05-06 23:34:55"
"Rivo Zängov (Eraser)",,0,0,0,0,0,0,0,"2020-10-13 04:38:26"
ashik8113,,0,0,0,0,0,0,0,"2022-04-13 11:58:26"
deepbird,,0,0,0,0,0,0,0,"2022-04-11 03:21:05"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-10-27 15:34:36"
Elham1361,,0,0,0,0,0,0,0,"2018-10-27 12:01:06"
"Ahnaf Tajwar (atn4404)",,0,0,0,0,0,0,0,"2018-10-16 11:13:30"
martyaberger,,0,0,0,0,0,0,0,"2019-01-01 18:48:08"
AsadullahIlyas,,0,0,0,0,0,0,0,"2019-01-04 06:14:15"
"akmal shafiq (mohdakmalshafiq)",,0,0,0,0,0,0,0,"2021-11-01 01:04:50"
"Sylwuskak (sylwuskak)",Polish,0,0,0,1,0,0,0,"2022-01-25 04:19:53"
"Yunsu Kim (yunsukim86)",Korean,0,0,0,2,0,0,0,"2022-01-14 06:33:43"
"Pumpith Ungsupanit (pumpithu)",,0,0,0,0,0,0,0,"2019-01-19 23:47:57"
"Nat Fomicheva (natac)",Russian,0,0,0,3,0,0,0,"2019-01-25 14:35:02"
HemanthMeda,Telugu,0,0,0,4,0,0,0,"2021-12-01 14:02:14"
"darkkingredian (rediancool)",,0,0,0,0,0,0,0,"2021-07-27 16:04:32"
catemlitten,Japanese,0,0,0,1,0,0,0,"2021-11-17 15:06:02"
"Said Tahsin Dane (tasomaniac)",,0,0,0,0,0,0,0,"2021-09-25 05:31:01"
"Matus Zdansky (matuszdansky)",,0,0,0,0,0,0,0,"2019-10-20 13:52:24"
mdrobulis,,0,0,0,0,0,0,0,"2018-05-24 01:40:42"
valney.faria,"Portuguese, Brazilian",0,0,0,1,0,0,0,"2020-02-02 14:45:02"
"Petros Bleyan (coolbleyan)",Russian,0,0,0,14,0,0,0,"2017-08-18 18:37:18"
"Карлен Шаухаев (KarlenShaukhaev)",,0,0,0,0,0,0,0,"2020-04-27 08:53:49"
"Shuvashish Sahoo (shuvashish76)",,0,0,0,0,0,0,0,"2020-09-17 09:10:09"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-01-05 16:56:12"
"Dagna Q (dagnaq)",,0,0,0,0,0,0,0,"2017-08-06 01:42:52"
Sandhu564.,,0,0,0,0,0,0,0,"2020-12-14 01:27:45"
AhmedDz,Arabic,0,0,0,1,0,0,0,"2017-12-31 10:12:31"
"Quentin Hibon (hiq)",,0,0,0,0,0,0,0,"2021-02-07 16:39:31"
"Ahmed Nazir (ahmednazir333)",,0,0,0,0,0,0,0,"2018-05-06 12:10:27"
"박인호 (wphestiraid)",Korean,0,0,0,2,0,0,0,"2018-01-05 00:33:14"
Raulbertassi,,0,0,0,0,0,0,0,"2018-01-07 17:23:18"
"Javid IRAN (twitteriran98)",Persian,0,0,0,1,0,0,0,"2017-11-25 16:47:25"
"Wellington Ribeiro (wellington.rib)",,0,0,0,0,0,0,0,"2017-11-16 07:32:25"
dimateos,,0,0,0,0,0,0,0,"2021-01-10 06:29:52"
"Balaji Jayaraman (jkbalaji1103)",,0,0,0,0,0,0,0,"2017-10-30 22:12:27"
"reza golestanzadeh (reza.golestanzadeh)",Persian,0,0,0,1,0,0,0,"2020-10-21 12:07:20"
"Muhammet Furkan ALMACI (furkan.almaci)",Turkish,0,0,0,1,0,0,0,"2017-10-29 13:44:56"
dongchen.yue,German,0,0,0,4,0,0,0,"2020-09-12 15:05:59"
"Алтынбек Наурызғали (altinbeknaurizgali)",Russian,0,0,0,1,0,0,0,"2020-08-12 13:03:49"
rooban23,,0,0,0,0,0,0,0,"2020-09-15 11:49:14"
NairaDNV,Spanish,0,0,0,9,0,0,0,"2018-01-05 19:10:33"
"Katherine Alexandra Flórez Ramírez (katherine.florez12)",Spanish,0,0,0,46,0,0,0,"2018-01-20 02:18:32"
Itch,,0,0,0,0,0,0,0,"2017-10-16 09:18:42"
"Yasin Okumus (lacivert)",Turkish,0,0,0,1,0,0,0,"2018-02-07 04:13:51"
"Eduard Boboc (edi.boboc33)",Romanian,0,0,0,4,0,0,0,"2019-12-16 09:08:39"
Hayder21,,0,0,0,0,0,0,0,"2019-12-31 10:56:24"
"Eliška Roubalová (roubaeli)",Czech,0,0,0,6,0,0,0,"2019-12-31 12:47:29"
Fazy1380,,0,0,0,0,0,0,0,"2021-04-10 11:02:53"
"Arttu Ylhävuori (arttu.ylhavuori)",,0,0,0,0,0,0,0,"2019-07-24 15:03:42"
"Alan Jeon (skyisle)",Korean,1,2,0,8,0,0,0,"2018-01-09 10:46:00"
"박찌 (perpact20)",Korean,1,1,0,0,0,0,0,"2018-02-10 10:11:44"
"Patrick Pimenta (trickap1)","Portuguese, Brazilian",1,1,0,0,0,0,0,"2018-12-01 14:31:21"
"Kan Black (kanblack.va)",Vietnamese,1,2,0,0,0,1,0,"2019-01-15 03:50:10"
"Maria Fefelova (mashafefel)",Russian,1,1,0,0,0,0,0,"2019-05-18 02:03:56"
"Anastasiia Bondarenko (nastasya.bondarenko.97)",Russian,1,1,0,0,0,0,0,"2019-06-07 17:43:08"
REMOVED_USER,Russian,1,2,0,6,1,0,1,"2019-12-26 05:37:01"
"Luca Gori (grolcu)",Italian,1,2,0,0,0,0,0,"2020-09-26 23:26:15"
jonesses,German,1,1,0,1,0,0,1,"2021-01-01 08:03:18"
"monir s (ms.alam)",Persian,1,1,0,1,0,0,0,"2022-05-23 06:34:00"
"Daniel Luque (LuqueDaniel)",Spanish,1,1,0,0,0,0,0,"2022-06-30 20:37:07"
Liboide,Spanish,1,1,0,0,0,0,0,"2022-11-03 23:57:45"
"K RITE (kriteshojha5)",Hindi,1,1,0,1,0,0,0,"2024-08-14 17:28:55"
"Angelos (angelos1993)",Arabic,1,1,0,0,0,0,0,"2024-11-20 07:38:18"
"Bora Atıcı (Brtc)",Turkish,1,2,0,0,0,0,0,"2025-03-07 20:33:19"
EmanAmini,,0,0,0,0,0,0,0,"2017-03-31 13:27:43"
AnggaRifandi,,0,0,0,0,0,0,0,"2017-03-31 19:28:35"
"Lori Amico (lavodkaclyde2323)",Italian,0,0,0,1,0,0,0,"2017-04-09 10:08:13"
"Florian Stuhlmann (stuhlmann)",German,0,0,0,10,0,0,0,"2017-04-15 04:04:00"
Kamalakannan,,0,0,0,0,0,0,0,"2017-05-14 11:40:23"
farbod66,Persian,0,0,0,1,0,0,0,"2018-01-20 11:04:23"
"vi ve (VimalV)",,0,0,0,0,0,0,0,"2021-02-08 02:35:45"
"Éjbãss Übbeî (littlebittlebottle)",Norwegian,0,0,0,152,0,0,0,"2017-07-05 21:12:02"
"LeMeD (LeMeS)",French,0,0,0,2,0,0,0,"2021-02-06 15:35:00"
BongTran,Vietnamese,0,0,0,2,0,0,0,"2018-04-24 05:16:07"
REMOVED_USER,Czech,0,0,0,18,0,0,0,"2018-03-27 06:19:52"
mushin,,0,0,0,0,0,0,0,"2020-02-02 04:08:05"
"Mateusz Teteruk (mttet)",Polish,0,0,0,1,0,0,0,"2021-01-23 13:09:59"
"Sarah BCNN (fsarahboucenna)",French,0,0,0,16,0,0,0,"2018-02-11 11:07:36"
"Dagna Q (dagnaq)",,0,0,0,0,0,0,0,"2017-08-06 01:42:52"
"Petros Bleyan (coolbleyan)",Russian,0,0,0,14,0,0,0,"2017-08-18 18:37:18"
Itch,,0,0,0,0,0,0,0,"2017-10-16 09:18:42"
"Muhammet Furkan ALMACI (furkan.almaci)",Turkish,0,0,0,1,0,0,0,"2017-10-29 13:44:56"
"Balaji Jayaraman (jkbalaji1103)",,0,0,0,0,0,0,0,"2017-10-30 22:12:27"
"Wellington Ribeiro (wellington.rib)",,0,0,0,0,0,0,0,"2017-11-16 07:32:25"
"Javid IRAN (twitteriran98)",Persian,0,0,0,1,0,0,0,"2017-11-25 16:47:25"
REMOVED_USER,Czech,0,0,0,1,0,0,0,"2017-12-24 04:08:27"
AhmedDz,Arabic,0,0,0,1,0,0,0,"2017-12-31 10:12:31"
"박인호 (wphestiraid)",Korean,0,0,0,2,0,0,0,"2018-01-05 00:33:14"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-01-05 16:56:12"
NairaDNV,Spanish,0,0,0,9,0,0,0,"2018-01-05 19:10:33"
Raulbertassi,,0,0,0,0,0,0,0,"2018-01-07 17:23:18"
"Katherine Alexandra Flórez Ramírez (katherine.florez12)",Spanish,0,0,0,46,0,0,0,"2018-01-20 02:18:32"
farbod66,Persian,0,0,0,1,0,0,0,"2018-01-20 11:04:23"
droidahmed,Arabic,0,0,0,7,0,0,0,"2018-01-31 02:18:49"
"Yasin Okumus (lacivert)",Turkish,0,0,0,1,0,0,0,"2018-02-07 04:13:51"
"Sarah BCNN (fsarahboucenna)",French,0,0,0,16,0,0,0,"2018-02-11 11:07:36"
T-v-Gerwen,Dutch,0,0,0,47,0,0,0,"2018-03-02 10:26:33"
"عبد الناصر سعيد الثبيتي (asaeed)",,0,0,0,0,0,0,0,"2018-03-13 02:09:35"
REMOVED_USER,Czech,0,0,0,18,0,0,0,"2018-03-27 06:19:52"
BongTran,Vietnamese,0,0,0,2,0,0,0,"2018-04-24 05:16:07"
"Ahmed Nazir (ahmednazir333)",,0,0,0,0,0,0,0,"2018-05-06 12:10:27"
mdrobulis,,0,0,0,0,0,0,0,"2018-05-24 01:40:42"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-08-24 00:17:43"
"Sri Harsha Bhogi (sriharshabhogi)",,0,0,0,0,0,0,0,"2018-09-02 05:31:53"
philfr49,French,0,0,0,2,0,0,0,"2018-09-03 14:20:32"
"Ahnaf Tajwar (atn4404)",,0,0,0,0,0,0,0,"2018-10-16 11:13:30"
Elham1361,,0,0,0,0,0,0,0,"2018-10-27 12:01:06"
REMOVED_USER,,0,0,0,0,0,0,0,"2018-10-27 15:34:36"
"Никита Карамов (nikita.karamoff)",Russian,0,0,0,10,0,0,0,"2018-10-29 03:57:21"
martyaberger,,0,0,0,0,0,0,0,"2019-01-01 18:48:08"
AsadullahIlyas,,0,0,0,0,0,0,0,"2019-01-04 06:14:15"
"Pumpith Ungsupanit (pumpithu)",,0,0,0,0,0,0,0,"2019-01-19 23:47:57"
"Nat Fomicheva (natac)",Russian,0,0,0,3,0,0,0,"2019-01-25 14:35:02"
ava_rfie,Persian,0,0,0,1,0,0,0,"2019-06-09 16:19:24"
"George Merkulov (george142.emarket)",Russian,0,0,0,11,0,0,0,"2019-06-09 19:47:02"
sanyoniket,,0,0,0,0,0,0,0,"2019-07-23 12:58:40"
"Arttu Ylhävuori (arttu.ylhavuori)",,0,0,0,0,0,0,0,"2019-07-24 15:03:42"
"Равиль Мифтахов (ravilmif47)",Russian,0,0,0,1,0,0,0,"2019-08-12 21:58:30"
Irsgram,Russian,0,0,0,1,0,0,0,"2019-09-30 16:42:20"
"Matus Zdansky (matuszdansky)",,0,0,0,0,0,0,0,"2019-10-20 13:52:24"
shuvo786,,0,0,0,0,0,0,0,"2019-11-13 00:18:12"
EwanB,,0,0,0,0,0,0,0,"2019-11-19 10:04:38"
"Eduard Boboc (edi.boboc33)",Romanian,0,0,0,4,0,0,0,"2019-12-16 09:08:39"
Hayder21,,0,0,0,0,0,0,0,"2019-12-31 10:56:24"
"Eliška Roubalová (roubaeli)",Czech,0,0,0,6,0,0,0,"2019-12-31 12:47:29"
REMOVED_USER,,0,0,0,0,0,0,0,"2020-02-01 03:47:48"
mushin,,0,0,0,0,0,0,0,"2020-02-02 04:08:05"
valney.faria,"Portuguese, Brazilian",0,0,0,1,0,0,0,"2020-02-02 14:45:02"
"Elmo (oberknecht)",,0,0,0,0,0,0,0,"2020-04-16 08:45:50"
"Карлен Шаухаев (KarlenShaukhaev)",,0,0,0,0,0,0,0,"2020-04-27 08:53:49"
"Edmunds Edmundam (edmundam)",,0,0,0,0,0,0,0,"2020-06-01 14:18:18"
"Алтынбек Наурызғали (altinbeknaurizgali)",Russian,0,0,0,1,0,0,0,"2020-08-12 13:03:49"
dongchen.yue,German,0,0,0,4,0,0,0,"2020-09-12 15:05:59"
rooban23,,0,0,0,0,0,0,0,"2020-09-15 11:49:14"
REMOVED_USER,,0,0,0,0,0,0,0,"2020-09-17 09:10:09"
"Arjun K. (arjunkdot)",,0,0,0,0,0,0,0,"2020-09-20 11:16:18"
"Rivo Zängov (Eraser)",,0,0,0,0,0,0,0,"2020-10-13 04:38:26"
"reza golestanzadeh (reza.golestanzadeh)",Persian,0,0,0,1,0,0,0,"2020-10-21 12:07:20"
Sandhu564.,,0,0,0,0,0,0,0,"2020-12-14 01:27:45"
dimateos,,0,0,0,0,0,0,0,"2021-01-10 06:29:52"
"Mateusz Teteruk (mttet)",Polish,0,0,0,1,0,0,0,"2021-01-23 13:09:59"
"LeMeD (LeMeS)",French,0,0,0,2,0,0,0,"2021-02-06 15:35:00"
"Quentin Hibon (hiq)",,0,0,0,0,0,0,0,"2021-02-07 16:39:31"
"vi ve (VimalV)",,0,0,0,0,0,0,0,"2021-02-08 02:35:45"
Fazy1380,,0,0,0,0,0,0,0,"2021-04-10 11:02:53"
"Saiprasath B (Saiprasath)",,0,0,0,0,0,0,0,"2021-07-11 11:10:41"
"darkkingredian (rediancool)",,0,0,0,0,0,0,0,"2021-07-27 16:04:32"
"Samuel Przeździęk (samek22)",Polish,0,0,0,1,0,0,0,"2021-08-01 00:49:01"
"Manny Farsangy (manifarsangi)",Persian,0,0,0,12,0,0,0,"2021-08-10 05:32:28"
"Masataka Yakura (myakura)",Japanese,0,0,0,1,0,0,0,"2021-09-03 22:10:36"
"Said Tahsin Dane (tasomaniac)",,0,0,0,0,0,0,0,"2021-09-25 05:31:01"
"akmal shafiq (mohdakmalshafiq)",,0,0,0,0,0,0,0,"2021-11-01 01:04:50"
catemlitten,Japanese,0,0,0,1,0,0,0,"2021-11-17 15:06:02"
HemanthMeda,Telugu,0,0,0,4,0,0,0,"2021-12-01 14:02:14"
"Yunsu Kim (yunsukim86)",Korean,0,0,0,2,0,0,0,"2022-01-14 06:33:43"
"Sylwuskak (sylwuskak)",Polish,0,0,0,1,0,0,0,"2022-01-25 04:19:53"
"Pro AAA (pro1010)",Arabic,0,0,0,1,0,0,0,"2022-02-14 03:32:44"
"Baran Özavcı (n2141n)",Turkish,0,0,0,1,0,0,0,"2022-02-26 04:32:51"
deepbird,,0,0,0,0,0,0,0,"2022-04-11 03:21:05"
ashik8113,,0,0,0,0,0,0,0,"2022-04-13 11:58:26"
" (manuL96)",,0,0,0,0,0,0,0,"2022-05-06 23:34:55"
"Agnel (agnelwaghela)",,0,0,0,0,0,0,0,"2022-06-19 10:32:33"
"Ruslan Zaynetdinov (theRuslan)",Russian,0,0,0,6,0,0,0,"2022-07-06 10:48:31"
"Marcel (flaced)",German,0,0,0,1,0,0,0,"2022-08-19 15:19:26"
pixx1,German,0,0,0,6,0,0,0,"2022-08-22 00:38:13"
"Onder Nuray (ondernuray)",,0,0,0,0,0,0,0,"2022-08-30 08:16:27"
"Md Faridul Islam (mdfaridulislam509)",,0,0,0,0,0,0,0,"2022-09-04 06:25:20"
Felone,,0,0,0,0,0,0,0,"2022-09-10 08:04:02"
Sawwwwwplan,,0,0,0,0,0,0,0,"2022-09-10 11:35:14"
"Fatima (fatima.a)",Arabic,0,0,0,1,0,0,0,"2022-09-20 09:48:25"
DomiAlt,,0,0,0,0,0,0,0,"2022-10-02 15:44:26"
Erwindly,Polish,0,0,0,1,0,0,0,"2022-11-01 04:12:58"
"Deniz Çelik (DenizCelik)",,0,0,0,0,0,0,0,"2022-11-09 02:13:11"
Watashiwanilli,,0,0,0,0,0,0,0,"2022-11-14 10:12:21"
"Maxence LIGAN (Daddy_Caramel)",,0,0,0,0,0,0,0,"2022-12-23 04:43:30"
wstroobandt,Dutch,0,0,0,1,0,0,0,"2023-01-03 17:52:42"
"ニキホロブ蒼井 (abhigyahazra)",,0,0,0,0,0,0,0,"2023-01-08 21:37:53"
"Afrim Kamberi (afrimkamberi)",,0,0,0,0,0,0,0,"2023-01-17 05:20:06"
ViacheslavLabs,Ukrainian,0,0,0,5,0,0,0,"2023-01-21 15:34:40"
Basta,,0,0,0,0,0,0,0,"2023-03-04 16:13:57"
raselh,,0,0,0,0,0,0,0,"2023-03-15 03:33:21"
"Adrian Miozga (AdrianMiozga)",Polish,0,0,0,13,0,0,0,"2023-03-25 17:00:53"
"Atlas Steel (atlas.steel.erbil)",,0,0,0,0,0,0,0,"2023-05-16 05:23:32"
"Sathyakumar Ps (sathyakumar63)",,0,0,0,0,0,0,0,"2023-05-24 11:44:23"
"Abdul nafih (nafih_zain_)",,0,0,0,0,0,0,0,"2023-05-25 06:24:31"
"Bernhard (bernikr)",German,0,0,0,1,0,0,0,"2023-06-12 11:18:18"
"Anna Boda (annaboda08)",Hungarian,0,0,0,1,0,0,0,"2023-07-03 13:28:12"
"Rubén CH (chruben45)",Spanish,0,0,0,1,0,0,0,"2023-07-24 12:39:51"
"Vinicius (exteraDev)",,0,0,0,0,0,0,0,"2023-08-08 15:47:45"
"mugdad alhammad (alhammad5057)",,0,0,0,0,0,0,0,"2023-08-13 22:36:01"
"Arthur Waldes (arthurwaldes)",,0,0,0,0,0,0,0,"2023-08-22 15:38:12"
"Mahmoud Hatem (mahmoudhatem)",Arabic,0,0,0,1,0,0,0,"2023-09-12 05:12:34"
"Jacques Francky Salomon (jacquesfranckysalomon)",,0,0,0,0,0,0,0,"2023-10-14 20:55:30"
"Mohammad Hashem (hashemchattogram)",,0,0,0,0,0,0,0,"2023-10-27 02:15:39"
Aylinddd,Persian,0,0,0,1,0,0,0,"2023-11-07 22:50:37"
Dinock,German,0,0,0,1,0,0,0,"2023-11-10 07:08:23"
zelfoxx,German,0,0,0,12,0,0,0,"2023-11-22 11:11:44"
REMOVED_USER,,0,0,0,0,0,0,0,"2023-11-28 17:42:55"
"Dennis Li (Dennis_Li)","Chinese Simplified",0,0,0,1,0,0,0,"2023-12-24 21:12:43"
REMOVED_USER,Russian,0,0,0,5,0,0,0,"2024-01-01 17:15:06"
"Daniill l (daniill)",,0,0,0,0,0,0,0,"2024-01-12 02:42:52"
"NONE NAME (RagnarGraves)",Spanish,0,0,0,1,0,0,0,"2024-02-18 01:39:39"
lu21232512,,0,0,0,0,0,0,0,"2024-04-15 12:40:05"
"Oscariño (oscarinhooo)",,0,0,0,0,0,0,0,"2024-07-07 08:47:25"
"Vladimir Sveshnikov (proloxy)",Russian,0,0,0,6,0,0,0,"2024-07-12 03:27:39"
L0f3n,Swedish,0,0,0,2,0,0,0,"2024-08-06 17:13:50"
"Christer Fletcher (chrfle)",Swedish,0,0,0,2,0,0,0,"2024-08-15 04:15:49"
"Moaid alzawy (dodoalzawy200)",Arabic,0,0,0,1,0,0,0,"2024-09-18 12:17:31"
"Eduardo Ferreira (eduu)",,0,0,0,0,0,0,0,"2024-10-27 19:09:20"
"عبد الملك بلكم (aboodpvp555)",Arabic,0,0,0,1,0,0,0,"2024-12-12 02:42:14"
4Kio,Russian,0,0,0,1,0,0,0,"2024-12-12 12:31:25"
"رودينه (rwdynh874)",Arabic,0,0,0,1,0,0,0,"2024-12-24 18:31:33"
"zahra ghasemi (z.ghasemizahra)",Persian,0,0,0,1,0,0,0,"2024-12-29 04:36:27"
"Mustafa Işıksız (mustafalordon27)",Turkish,0,0,0,1,0,0,0,"2025-01-15 13:52:32"
"Ahlem Ben (ahlemben1513)",Arabic,0,0,0,1,0,0,0,"2025-02-12 11:09:57"
"Francisco Parra (Frn_7)",Spanish,0,0,0,1,0,0,0,"2025-02-18 22:57:05"
"mizumoto (yuta-mizumoto)",Japanese,0,0,0,2,0,0,0,"2025-03-03 18:35:56"
1 Name Languages Translated (Words) Target Words Approved (Words) Voted "+" votes received "-" votes received Winning (Words) Joined
2 Alinson Xavier (iSoron) Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Polish; Arabic; German; Korean; Greek; Catalan; Bulgarian; Hindi; Slovenian; Ukrainian; Serbian (Cyrillic); Czech; Indonesian; Croatian; Danish; Dutch; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Norwegian; Afrikaans; Slovak; Armenian; Serbian (Latin); Uyghur Portuguese, Brazilian; Japanese; Chinese Simplified; Italian; Spanish; Portuguese; French; Hungarian; Chinese Traditional; Turkish; Russian; Arabic; Polish; German; Korean; Bulgarian; Catalan; Greek; Slovenian; Hindi; Serbian (Cyrillic); Ukrainian; Czech; Danish; Dutch; Indonesian; Croatian; Romanian; Swedish; Basque; Persian; Finnish; Vietnamese; Tamil; Telugu; Hebrew; Esperanto; Afrikaans; Norwegian; Armenian; Slovak; Serbian (Latin); Uyghur 15497 18825 1308 0 1896 2094 84 111 4315 2016-03-05 18:35:27
3 Slobodan Simić (Слободан Симић) (slsimic) Serbian (Latin); Serbian (Cyrillic) 2054 2072 1831 1852 2114 2139 12 33 30 0 1991 2015 2021-02-03 14:26:07
4 Oglaigh Rystard (oglaignaheireann) dukelc Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian Slovak 1103 1107 1037 1052 1327 0 1 0 13 0 6 0 954 0 2017-03-31 09:13:19 2020-08-27 14:02:41
5 dukelc Oglaigh Rystard (oglaignaheireann) Slovak Ukrainian; Portuguese; Catalan; Greek; Basque; Romanian; Italian 1046 1103 993 1037 0 1327 0 1 0 22 0 13 0 954 2020-08-27 14:02:41 2017-03-31 09:13:19
6 David (Cliff122) Avalysion Swedish Georgian 1040 1057 1019 895 725 0 6 0 0 0 700 0 2020-01-21 13:56:55 2023-06-30 20:05:15
7 Omer I.S. (omeritzics) Mathew TK (mathew2006) Hebrew Malayalam 1040 1057 927 1885 1122 0 14 0 1 0 0 975 0 2020-10-11 20:10:51 2023-12-16 01:57:49
8 REMOVED_USER Hebrew 1051 944 1122 14 1 0 954 2020-10-11 20:10:51
9 David (Cliff122) Swedish 1040 1019 725 6 37 0 700 2020-01-21 13:56:55
10 Intan Ayunda (Intan_Ayunda) Indonesian 818 811 985 0 0 0 729 2020-10-14 07:51:58
11 Mihail Stefanov (MStefanov) dusanstrgar Bulgarian Slovenian 755 770 794 730 3 0 0 2 0 0 2 0 2017-03-31 16:09:02 2017-03-31 10:30:28
12 Mihail Stefanov (MStefanov) Bulgarian 755 794 3 0 2 4 2 2017-03-31 16:09:02
13 Osoitz Basque 751 683 0 9 0 0 3 2018-01-23 14:07:47
14 KMakoto Chinese Traditional 745 1146 949 0 0 0 745 2019-10-22 04:19:52
15 Evren (evrenkiymaz) Tomairuka Turkish Japanese 688 709 604 1842 0 1033 71 43 28 12 22 0 0 585 2020-10-04 03:39:16 2020-12-12 12:14:22
16 andaryon Evren (evrenkiymaz) Czech Turkish 681 688 606 604 0 108 71 0 31 0 22 0 2021-11-25 10:20:45 2020-10-04 03:39:16
17 andaryon Czech 681 606 0 108 21 0 0 2021-11-25 10:20:45
18 Antti Kallio (antti.kallio) Finnish 668 539 0 5 0 0 0 2021-07-03 05:54:44
19 David Nos (david.nos) Catalan; Spanish 667 731 0 0 1 0 0 2020-01-04 10:15:36
20 androide74 Italian 662 681 0 2 0 0 0 2020-02-06 15:46:28
21 Osoitz Dmitriy Bogdanov (di72nn) Basque Russian 655 643 595 589 0 1197 9 0 0 50 0 3 515 2018-01-23 14:07:47 2017-03-31 10:00:48
22 Dmitriy Bogdanov (di72nn) reyhoon Russian Persian 643 624 589 759 1197 0 0 1 36 3 0 2 515 0 2017-03-31 10:00:48 2020-10-01 18:17:23
Tomairuka Japanese 633 1636 909 43 0 0 564 2020-12-12 12:14:22
reyhoon Persian 624 759 0 1 3 1 0 2020-10-01 18:17:23
23 Saeed Esmaili (saaeed.es20) Persian 586 795 0 5 4 0 0 2020-11-26 15:41:15
24 fabian.bouchal German 548 527 0 6 0 4 3 5 72 2020-01-07 06:43:37
25 Isti (eisti) Hungarian 528 476 0 0 0 1 0 0 2020-12-03 12:02:51
26 boban77 Aravinth_Earth Czech Tamil 509 511 461 961 0 2 12 29 0 0 0 2020-04-30 13:18:24 2024-02-23 12:37:28
27 boban77 Czech 509 461 0 2 45 0 0 2020-04-30 13:18:24
28 Martim Parente (martimparente) Portuguese 505 542 0 38 0 0 0 2020-08-26 10:22:11
29 Yoav Argov (YoavArgov) Hebrew 501 461 0 0 1 8 91 2017-04-28 07:23:01
30 REMOVED_USER Norwegian 501 498 501 0 148 0 501 2017-07-05 19:02:25
31 chrrris1987 (Chrrris1987) Dutch 467 478 0 23 0 0 0 2020-02-03 05:26:04
32 黄克 (hk13127) Chinese Simplified 461 765 0 1 0 0 24 22 2020-01-17 23:16:03
33 Huy Ngo (huyngo) Vietnamese 461 695 0 1 0 0 0 2020-01-26 11:58:36
34 Arkadiusz Bubak (epitek) Polish 458 416 52 24 9 15 4 0 2020-11-05 05:11:58
35 Radek Kuklík (kuklik.radek) Czech 453 392 0 100 0 0 0 2022-10-08 10:04:24
36 marco.baturan Esperanto 452 452 0 0 0 0 0 2020-06-23 02:49:46
37 Sief Tarek (sieftarek135) Arabic 447 455 0 0 0 1 0 4 0 2021-02-07 14:35:21
38 Alparslan Şakçi (sakci) Turkish 436 372 0 118 1 2 0 0 2022-01-14 12:03:11
39 JY3 Chinese Simplified 427 432 727 741 295 298 0 1 2 0 222 227 2021-03-08 08:53:35
40 Samuel Guay (SamGuay) French 426 486 0 6 0 0 0 2020-06-25 07:14:38
41 Diana Karaseva (Sun_Dianka) Russian 399 373 0 10 1 0 209 2020-01-30 06:40:02
42 Alexander Jansson (dalecarlian) Swedish 396 406 507 0 0 29 3 6 399 2017-06-21 01:37:32
43 luiandresgonzalez Spanish 383 403 0 1 28 0 0 2020-07-11 14:20:44
44 Thamara Andrade (tkcandrade) Portuguese, Brazilian 380 387 0 0 1 0 239 2020-01-09 19:35:48
45 Sølv Ræven (soelvraeven) Danish 370 370 0 0 0 0 0 2020-11-28 16:46:18
46 strikeCunny2245 Icelandic 363 368 0 0 0 0 0 2023-08-07 08:05:53
47 Anh Quân (dangquanuet) Vietnamese 362 530 0 42 2 0 0 2017-10-29 12:27:44
48 Alexander Haronitakis (kanakis) Greek 349 372 0 0 0 0 0 2023-09-13 04:10:43
49 gapszi Hungarian 348 301 0 86 0 0 0 2019-04-08 01:35:54
50 Mahdi Nasiri (mahdi.nasiri) Persian 343 465 0 39 3 1 0 2017-07-14 09:17:25
51 Seoyul Korean 339 825 0 0 27 0 0 2017-06-21 08:11:39
52 Magimai Prakasam (magimai) Tamil 336 831 0 12 0 2 0 0 2018-04-15 21:16:08
53 Michael Malak (MichaelKMalak) Star7 (Star7-crowdin) Arabic Chinese Simplified 304 330 271 561 0 0 1 0 0 0 2020-05-26 19:47:58 2025-02-10 08:41:34
54 Blinkin Susanamesa Dutch Spanish 297 306 334 342 0 5 11 0 0 0 2021-06-14 10:30:05 2023-01-01 23:56:35
55 Michael Malak (MichaelKMalak) Arabic 304 271 0 0 4 2 0 2020-05-26 19:47:58
56 Elina Salminen (salminen.elina.m) Finnish 297 227 0 0 0 0 0 2021-01-06 01:28:57
57 ayane.m Blinkin Japanese Dutch 292 297 863 334 0 1 5 5 1 0 22 0 2019-11-20 03:28:26 2021-06-14 10:30:05
58 Marius Teufelweich (teufelweich) ayane.m German Japanese 267 292 272 863 611 0 4 1 13 8 1 0 146 23 2021-03-12 04:11:38 2019-11-20 03:28:26
59 c.m Greek 276 293 0 124 0 0 0 2024-07-13 14:49:43
60 Marius Teufelweich (teufelweich) German 267 272 611 4 23 3 146 2021-03-12 04:11:38
61 Sumin Son (todaypp) Korean 266 221 0 7 0 0 0 2023-06-09 05:28:30
62 hypnotichemionus Chinese Simplified 249 430 0 0 8 0 19 2020-03-08 01:46:25
63 Israa Z (sosozozo) Arabic 240 266 0 81 14 0 3 2017-11-27 14:10:50
64 cobalt59 German 237 234 0 1 24 1 132 2017-06-05 05:18:33
65 beriain Basque 234 235 0 0 2 0 0 2017-03-31 15:42:28
66 pnhpnh Vietnamese 225 343 0 1 3 0 0 2017-11-27 12:06:07
67 Dika Fitrian Dwi Putra (OsamuDazai) Indonesian 221 215 0 0 0 0 48 2020-07-13 04:40:27
68 easyrepro Telugu 214 297 0 0 4 0 0 2020-06-12 12:52:10
69 taras-ko Ukrainian 211 183 0 1 4 0 19 2017-10-26 16:52:22
70 vinayak sharma (vinayak0504) Hindi 211 456 0 0 0 0 0 2023-05-18 18:31:51
71 sojusnik German 207 200 1 0 30 0 66 2017-04-03 17:11:56
72 Andrij Mizyk (andmizyk) Andrij Mizyk (andm) Ukrainian 204 178 0 40 0 1 0 53 2021-04-01 03:56:20
73 Heru Yen (heruyen) Indonesian 201 201 0 0 0 0 25 2020-06-29 18:39:15
74 Vijaykumar Borkar (vjkumar) Hindi 200 364 0 11 0 0 0 2021-08-06 16:12:15
75 _translator French 199 227 0 11 0 0 0 2021-07-06 07:54:12
76 bearsdens Romanian 198 210 0 0 0 0 0 2022-08-28 17:08:33
77 Ishmaeel Turkish 193 174 0 129 17 6 0 2017-10-04 03:54:00
78 oscfd REMOVED_USER Spanish 192 201 0 2 4 5 0 0 2021-05-21 17:58:22
79 bruhwut Vietnamese 189 292 0 1 0 0 0 2021-05-21 07:16:30
80 Aputsiak Niels Janussen (aputtu) Danish 187 200 0 0 0 0 0 2019-08-28 05:47:42
81 fbruna17 Danish 181 179 0 1 0 0 0 2021-01-28 15:48:47
82 Bryanx Dutch 179 168 0 5 2 0 0 2019-11-21 17:08:12
83 Omry Cohen (omrycohen) Ivan Vlahov (vlahovivan) Hebrew Croatian 175 179 156 176 0 1 0 0 0 33 0 2021-01-18 07:33:23 2024-01-25 08:12:11
84 Omry Cohen (omrycohen) Hebrew 175 156 0 1 0 0 12 2021-01-18 07:33:23
85 Pierre GALIEGUE (pierre.galiegue) French 171 194 0 24 4 0 0 2020-08-16 11:41:35
86 plitwin Polish 168 151 0 2 31 55 0 49 2021-01-20 06:18:37
87 DionysosDV Greek 165 153 0 0 0 27 0 4 0 2021-02-27 19:05:25
88 Gustavo Lima (GustavoLima) Portuguese 158 177 0 1 4 10 0 2020-08-26 10:35:05
89 Alex V. (elvitalex) Romanian 154 166 0 24 0 0 0 2022-08-03 17:40:00
90 Ravi Rami (ramiravi) Hindi 151 248 0 0 0 0 0 2021-10-10 09:19:40
91 Lương Vĩnh Khang (LuongVinhKhang) Vietnamese 144 256 0 0 46 1 0 2017-08-10 10:05:58
92 azzamsa Indonesian 142 136 0 48 0 1 26 2017-06-16 18:29:45
93 yoding (yodingc) Chinese Traditional; Chinese Simplified 141 271 0 10 0 0 0 2021-07-07 01:45:45
94 Neysa Nasywa (neysanasywa) Indonesian 140 141 0 0 0 0 60 2020-11-18 10:32:10
95 mohmans Arabic 139 141 0 12 1 7 0 1 0 2020-11-23 02:48:00
96 Eilif Adelvice (adelvice) Spanish 139 154 0 96 1 6 0 0 2021-08-05 07:20:21
97 Mohammed Imthath (mimthath4) Tamil 136 274 0 0 11 13 0 1 0 2018-02-15 22:41:15
98 carllacan Catalan 134 155 0 2 0 0 0 2021-11-13 13:12:07
99 roptat French 132 154 0 112 89 5 0 2017-04-19 16:54:47
100 Trần Thái (tranhoangthai2001) Vietnamese 127 186 0 8 1 0 0 2018-03-01 10:51:39
101 OP Smosher (teenwolffan44) Serbian (Cyrillic) 124 122 0 0 0 0 18 2020-11-05 09:41:35
102 Tad Wohlrapp (TadWohlrapp) German 124 122 0 0 2 0 0 2022-06-28 04:55:41
103 4001982248998 Esperanto 122 119 0 0 0 0 0 2017-10-08 04:13:02
104 StoP4Me (Lcqp) Romanian 121 119 0 0 3 6 0 0 2018-05-06 18:51:59
105 alalloush Arabic 118 129 0 2 14 17 3 6 0 2017-03-31 12:37:17
106 Brenda Correa (brenda.14) Spanish 117 127 0 0 0 1 0 2022-05-16 02:34:13
107 Sebastian05067 Spanish 114 133 0 55 32 0 0 2017-05-14 00:48:16
108 Tanya (MagicUnderHood) Russian 114 98 0 19 0 0 54 2019-04-21 10:44:03
109 Sebastian05067 REMOVED_USER Spanish Arabic 114 111 133 106 0 55 22 28 23 0 3 0 2017-05-14 00:48:16 2018-01-05 07:01:45
REMOVED_USER Arabic 111 106 0 22 22 2 0 2018-01-05 07:01:45
Iabin Arteaga (iabin) Spanish 108 111 0 4 21 0 0 2017-08-26 21:08:54
110 Ivan Krušlin (krux3r) Croatian 108 122 503 0 0 0 108 2017-03-31 09:15:24
111 2kaafone Iabin Arteaga (iabin) Finnish Spanish 105 108 90 111 0 0 4 0 21 0 1 0 2019-08-12 06:58:48 2017-08-26 21:08:54
112 REMOVED_USER Finnish 105 90 0 0 0 0 0 2019-08-12 06:58:48
113 Adam Jurkiewicz (hasztagg) Polish 104 105 529 0 0 0 104 2017-03-31 09:50:51
114 PILHA PARK (pilhaha) Korean 101 88 0 0 0 0 0 2023-06-30 23:51:41
115 just a name bro (justanamebr0) Danish 98 109 0 0 1 0 0 2019-06-19 11:57:55
116 Nam Nguyen (namnl2706) Vietnamese 95 137 0 0 0 0 0 2020-08-18 23:02:33
117 손유정 (yuwon1213) Korean 95 57 0 0 1 0 3 0 2021-03-30 05:25:33
118 ranmagen Hebrew 91 78 0 0 0 0 0 2021-02-16 05:44:31
119 LoneWanderer Chinese Traditional 90 137 0 4 0 0 0 2020-09-29 05:24:48
120 ikkaz Indonesian 89 84 0 5 0 0 4 2019-09-02 19:58:54
121 Vo - (voyl) Chinese Traditional 89 126 0 0 5 0 0 2020-09-02 23:34:42
122 Irene K (Heaun) Korean 88 75 0 25 0 2 0 0 2020-03-16 11:31:12
123 Prosta4ok_ua Ukrainian 87 84 0 1 0 0 17 2020-01-23 19:43:41
124 Kumar Anand (kumar0500) Hindi 87 125 0 0 0 0 0 2020-11-07 02:46:09
125 G.kio Russian 87 82 0 0 1 0 0 2023-08-24 19:43:00
126 Ohad Edri (ohadalte) Hebrew 85 79 0 0 1 3 13 2020-07-04 03:42:09
127 helectron Radu Cebotari (wildProgrammer) Persian Romanian 84 102 92 0 1 0 1 0 0 2021-03-02 04:10:51 2020-02-05 01:20:00
128 Radu Cebotari (wildProgrammer) helectron Romanian Persian 84 92 102 0 1 0 1 0 0 2020-02-05 01:20:00 2021-03-02 04:10:51
129 Bruces Lee (aplusbdesign) Korean 82 66 0 0 0 2 0 0 2021-08-23 11:27:18
Israa Z (sosozozo) Arabic 79 87 0 43 14 0 3 2017-11-27 14:10:50
Sofia Neves (sofiasonev) Portuguese, Brazilian 79 84 0 1 0 0 46 2020-03-12 18:19:46
Jacob Roller (jdr28070) Korean 79 61 0 0 1 0 0 2020-01-03 11:36:40
130 Tiralka French 79 91 0 92 1 0 0 2018-02-09 18:39:01
131 Jacob Roller (jdr28070) Korean 79 61 0 0 1 1 0 2020-01-03 11:36:40
132 Sofia Neves (sofiasonev) Portuguese, Brazilian 79 84 0 1 0 0 46 2020-03-12 18:19:46
133 Toni Mustonen (toni.mustonen) Finnish 78 72 0 0 5 0 0 2017-09-02 05:34:12
Michael (quelbs) German 76 75 0 1 0 0 39 2020-08-18 07:39:26
134 Fauz Aladeem (topfauz) Arabic 76 77 0 0 0 1 0 2020-02-21 22:46:12
135 Radoslaw Biernacki (radoslaw.biernacki) Michael (quelbs) Polish German 70 76 74 75 0 56 1 1 0 0 1 39 2020-12-15 17:55:31 2020-08-18 07:39:26
136 Oliver Gronowski (OliverGronowski) Anna Maria Stålberg (stalberg.annamaria) German Swedish 70 76 69 77 0 5 111 2 4 0 0 2021-05-14 16:37:10 2023-01-16 04:08:25
137 Radoslaw Biernacki (radoslaw.biernacki) Polish 70 74 0 56 5 0 1 2020-12-15 17:55:31
138 Oliver Gronowski (OliverGronowski) German 70 69 0 5 3 0 0 2021-05-14 16:37:10
139 mimizuk Japanese 68 193 0 0 2 1 39 2022-05-18 10:10:38
140 Ryeore Polish 68 61 0 66 0 0 0 2022-07-27 12:22:33
141 RealDonald Dutch 67 69 0 121 10 0 0 2017-06-23 20:10:12
142 Dpd Eng (dpdeng) Korean 67 48 0 0 1 0 0 2022-10-15 10:56:44
143 sirekanyan Armenian; Russian 66 65 0 0 0 0 0 2020-04-18 11:32:52
144 Константин К. (kocyak1991) Russian 64 60 0 0 1 2 0 2018-06-10 13:39:37
145 yukitsubaki Japanese 64 185 0 32 0 0 36 2020-01-01 13:17:44
146 Suuis Hindi 64 110 0 0 0 0 0 2023-07-02 11:50:22
147 Laura Sophie (laurasophie20) German 62 67 0 4 0 0 0 2018-01-06 14:21:24
148 raden20 Indonesian 61 62 177 0 1 0 64 2017-04-09 22:04:23
149 Peter Williams (williamspete001) y (veggente) Japanese Korean 60 61 173 56 0 2 0 0 0 1 3 0 2020-01-01 13:17:44 2022-06-28 10:41:18
150 Jan Wojtecki (j4nw) Polish 58 46 0 0 0 0 26 2017-11-02 05:42:14
151 Deepak Bharathi (deepakbharathi1994) Tamil 56 107 0 0 11 13 4 0 2017-09-17 08:00:31
152 Андрій Козицький (andriikozytskyi1108) Ukrainian 52 52 0 0 1 0 0 2018-10-22 01:45:08
153 Nil riera (nilriera2000) Catalan 52 61 0 1 2 0 0 2021-06-22 16:37:44
Neoone (Neooneqq) Romanian 51 54 0 0 0 0 0 2022-05-05 20:42:11
154 REMOVED_USER Italian 51 52 0 2 0 0 0 2017-08-21 05:15:31
155 govindap Japanese; Hindi 51 114 0 6 1 3 0 1 0 2020-06-02 20:15:52
156 Neoone (Neooneqq) Romanian 51 54 0 0 0 0 0 2022-05-05 20:42:11
157 Mare Geldenhuys (mare.geldenhuys) Afrikaans 50 57 0 0 0 0 0 2017-10-20 18:00:14
Mahmoud Magdy (M7moudManson) Arabic 49 60 0 6 8 1 0 2021-08-21 09:01:38
158 Behnood HRazy (behnoodhr) Persian 49 70 0 0 0 0 0 2017-11-25 10:57:21
159 Mahmoud Magdy (M7moudManson) Arabic 49 60 0 6 12 6 0 2021-08-21 09:01:38
160 J3ll3nl Dutch 48 48 0 0 17 1 3 2017-03-31 11:56:09
161 tat bz (Tat_i) German 48 56 0 55 0 1 27 2021-03-26 05:12:54
vach Armenian 47 36 0 0 0 0 0 2020-04-18 16:53:12
162 Andrew Firnes (Anechan) Russian 47 47 0 3 0 0 29 2019-09-18 09:51:59
163 andowero Czech 47 38 0 0 3 8 0 0 2020-01-20 02:29:01
164 vach Armenian 47 36 0 0 0 0 0 2020-04-18 16:53:12
165 Rahul Shishodia (rahul.shishodia.10) Hindi 46 85 0 6 5 1 0 2018-12-24 22:18:19
166 Coni Ragni (coni2ragnii) Spanish 46 46 0 0 0 0 0 2021-02-28 20:18:37
167 Cp0204 Chinese Simplified 45 72 0 0 0 0 0 2019-08-20 11:04:27
168 cc (cavaz) Italian 44 41 0 0 0 0 0 2017-04-01 04:21:08
169 Boban Jagertraum (boban40) Andrej Šutovský (16andrej.s) Czech Slovak 43 44 38 41 0 2 0 18 0 1 0 0 2017-03-31 09:39:16 2022-06-12 18:01:16
170 Kamil Dziadek (prso94) Boban Jagertraum (boban40) Polish Czech 43 39 38 0 0 2 6 31 0 1 0 2020-04-06 17:12:06 2017-03-31 09:39:16
171 Kamil Dziadek (prso94) Polish 43 39 0 0 11 0 0 2020-04-06 17:12:06
172 Balázs Keresztury (belidzs) Hungarian 42 41 501 0 7 0 38 2017-04-06 02:40:24
173 andreea.muscalagiu Romanian 42 52 0 1 0 0 0 2017-10-22 07:19:49
174 Me Me (gentelwom) Arabic 42 40 0 0 0 0 0 2020-11-08 20:44:01
Balázs Keresztury (belidzs) Hungarian 42 41 501 0 7 0 38 2017-04-06 02:40:24
Mateusz Duda (MateuszDuda) Polish 42 42 0 0 6 0 0 2021-08-17 11:27:11
175 Ali Elsheikh (aelsheikh1987) Arabic 42 41 0 0 0 0 0 2021-06-16 10:17:26
176 Ali Zali (stm19951995) Mateusz Duda (MateuszDuda) Persian Polish 40 42 60 42 0 0 0 20 0 0 2020-03-23 19:57:26 2021-08-17 11:27:11
177 Mr Habti (donhabti) Arabic 41 40 0 0 0 0 0 2023-02-20 10:52:50
178 Sofia Veijonen (Suklaa) (sofia.veijonen) Finnish 40 33 0 0 0 0 0 2018-03-07 09:24:22
179 dusanstrgar Neeraj Verma (verma.neeraj.in) Slovenian Hindi 39 40 41 65 0 0 0 1 0 0 2017-03-31 10:30:28 2018-07-23 07:16:41
180 Ali Zali (stm19951995) Persian 40 60 0 0 0 0 0 2020-03-23 19:57:26
181 Limin Lu (liminlu) Chinese Simplified 39 79 503 0 0 0 39 2017-03-31 09:49:35
182 Anshoe Tamil 38 65 0 14 0 3 0 0 2018-01-02 11:06:52
183 Pavel Protasov (pvphome) Russian 38 33 0 0 0 0 0 2024-02-09 03:40:33
184 anasshm Arabic 37 36 0 9 0 0 0 2019-01-27 04:07:22
185 hrexen Armenian 37 37 0 0 0 0 0 2020-12-09 02:30:34
186 Abdulrahman (D7M) REMOVED_USER Arabic Swedish 36 39 33 0 0 5 0 2 0 0 2020-01-29 18:55:30 2018-09-29 17:47:33
187 REMOVED_USER Abdulrahman (D7M) Swedish Arabic 36 33 39 0 5 0 1 4 0 0 2018-09-29 17:47:33 2020-01-29 18:55:30
xphsis Basque 36 31 0 0 0 0 0 2022-01-02 08:16:19
188 Maria Chushnyakova (maria.ch) Russian 36 31 0 3 0 0 0 2021-08-17 03:23:58
189 長谷川知里 (chase0213) xphsis Japanese Basque 34 36 138 31 0 13 0 0 0 24 0 2018-12-14 10:52:44 2022-01-02 08:16:19
190 Piotr Łuczyński (peterluczynski) 長谷川知里 (chase0213) Polish Japanese 33 34 30 138 0 6 13 10 0 0 2 32 2020-01-29 07:27:40 2018-12-14 10:52:44
Luis E. Perichon (luisperichon) Spanish 33 40 0 104 0 0 0 2017-09-04 13:46:06
191 milad farahani (miladfarmahini90) Persian 33 44 0 18 1 0 3 2017-08-31 16:09:00
192 Luis E. Perichon (luisperichon) Spanish 33 40 0 104 0 0 0 2017-09-04 13:46:06
193 Piotr Łuczyński (peterluczynski) Polish 33 30 0 6 17 0 2 2020-01-29 07:27:40
194 JoeLi Chinese Traditional 31 70 0 12 0 0 24 2017-06-25 05:32:48
andriikozytskyi2625 Ukrainian 31 23 0 0 0 0 0 2019-07-08 00:16:41
195 REMOVED_USER Russian 31 30 0 2 4 0 3 2018-12-03 23:55:47
196 Moastafa andriikozytskyi2625 Arabic Ukrainian 31 25 23 0 0 0 0 0 2020-07-06 11:37:53 2019-07-08 00:16:41
197 hamza gamal (hamzagamal4444) Moastafa Arabic 31 28 25 0 0 0 0 4 0 2020-08-03 15:23:34 2020-07-06 11:37:53
198 hamza gamal (hamzagamal4444) Arabic 31 28 0 0 1 0 0 2020-08-03 15:23:34
199 yancyn Chinese Simplified 30 40 0 0 0 0 1 2020-05-18 20:06:03
200 Siniša Sabljić (ssabljic) Croatian 30 37 0 0 0 0 0 2023-11-13 15:51:00
201 Ruud Schouten (ruudschouten) Dutch 29 32 0 41 3 0 0 2017-07-22 17:49:17
202 비니몬youtube (khj01025276475) Korean 29 25 0 0 0 0 1 0 2020-02-09 20:44:35
203 avelneve Indonesian 29 28 0 0 0 0 0 2022-04-13 13:26:10
204 bzhn Ukrainian 29 26 0 0 4 0 0 2022-06-18 17:09:13
205 Gergő Mihály (mihalygergo97) Hungarian 28 69 0 0 0 0 0 2024-02-13 08:35:57
206 Niraj Yadav (neverforgetniraj) Hindi 26 48 0 0 0 0 0 2017-04-11 02:26:50
Aaron Dalton (Perlkonig) French 26 25 0 141 1 0 0 2018-01-14 12:58:19
Jonny I (jonny99dj) Italian 26 26 0 5 0 0 0 2017-10-07 07:35:34
207 Guillaume Collic (gcollic) French 26 28 0 126 11 0 0 2017-05-05 16:13:00
208 Pan_Filuta Jonny I (jonny99dj) Czech Italian 25 26 21 26 0 5 8 0 0 3 0 2017-04-29 12:55:14 2017-10-07 07:35:34
209 Aaron Dalton (Perlkonig) French 26 25 0 141 1 0 0 2018-01-14 12:58:19
210 Pan_Filuta Czech 25 21 0 5 11 0 3 2017-04-29 12:55:14
211 Eddie (eddieattaboy) Chinese Traditional 25 34 0 1 0 0 0 2020-11-04 21:48:05
212 eduard83 (barbany.eduard) REMOVED_USER Catalan 24 25 0 2 0 0 0 2019-06-26 14:59:47
A Aa (ylayzlmimashisafyoutub) Arabic 23 33 0 34 1 1 0 2021-09-27 15:34:26
213 Caner Başaran (basarancaner) Turkish 23 21 0 0 26 1 0 2017-04-09 06:34:59
214 Ľuboš Čaky (lubos.caky) Slovak 23 22 0 0 0 0 0 2019-07-02 16:51:44
215 Neeraj Verma (verma.neeraj.in) A Aa (ylayzlmimashisafyoutub) Hindi Arabic 22 23 37 33 0 0 34 1 3 0 2 0 2018-07-23 07:16:41 2021-09-27 15:34:26
gnu-ewm Polish 22 23 0 6 2 0 0 2021-02-24 03:42:01
216 hodanli Turkish 22 26 0 0 1 0 0 2017-11-03 14:33:41
217 REMOVED_USER Polish 22 23 0 6 9 0 0 2021-02-24 03:42:01
218 Alcarkse (alexis.brusle) French 21 25 0 7 11 0 0 2017-08-06 09:32:29
219 Hugo Nogueira (hfrnogueira86) Portuguese 21 22 0 0 0 0 0 2023-01-09 22:51:24
220 Shashwat (goforgold) Hindi 20 33 0 0 0 0 0 2020-05-17 10:34:42
221 olbotta Italian 20 25 0 2 0 0 0 2021-06-06 04:22:55
can13 Turkish 19 14 0 8 0 0 0 2021-01-03 10:39:03
사자솥 (toke1597) Korean 19 19 0 0 0 0 0 2020-02-04 13:36:11
KenKailer Arabic 19 25 0 0 0 0 0 2022-05-10 06:16:54
222 İsa Eş (IsaEs) Turkish 19 17 0 0 6 2 0 2017-06-20 07:30:22
223 Magdalena Urbańczyk (madziia139) Polish 19 19 0 0 0 0 0 2017-10-21 03:01:04
224 sheeCesu French 19 18 0 48 4 0 0 2017-12-21 17:01:39
225 사자솥 (toke1597) Korean 19 19 0 0 0 0 0 2020-02-04 13:36:11
226 can13 Turkish 19 14 0 8 0 0 0 2021-01-03 10:39:03
227 KenKailer Arabic 19 25 0 0 0 0 0 2022-05-10 06:16:54
228 axikman11111 Uyghur 18 19 0 0 0 0 0 2018-10-13 12:25:31
229 Adeline31 Sanjay Krishna (sjaykh) French Malayalam 17 18 20 42 0 3 0 0 0 0 2019-12-06 00:00:11 2024-06-01 08:57:37
230 Hoon Jung (hooni100) Chuang-Chen Chiu (peterChiu9952) Korean Chinese Traditional 17 18 10 28 0 0 0 0 0 2021-01-03 02:26:54 2024-07-02 09:36:59
231 takoyakibento AlexanderS Korean German 17 18 13 16 0 3 8 0 0 0 2020-08-01 08:44:15 2025-02-02 16:58:09
232 Ceara Lopez (cealopez) Spanish 17 18 0 0 5 1 0 2017-08-22 22:56:13
233 bretzel15 Adeline31 German French 16 17 20 0 0 3 0 1 0 0 2020-04-06 02:49:14 2019-12-06 00:00:11
234 DebatablySane takoyakibento Bulgarian Korean 16 17 15 13 0 48 3 0 0 0 2017-07-10 15:13:18 2020-08-01 08:44:15
235 Hoon Jung (hooni100) Korean 17 10 0 0 0 0 0 2021-01-03 02:26:54
236 Annelotte Dutch 17 20 0 0 0 0 0 2022-11-09 08:33:20
237 wppoqqqi Korean 17 18 0 4 0 0 0 2024-11-30 04:22:21
238 Şamil Ateşoğlu (m.samilatesoglu) Turkish 16 22 0 11 6 3 0 2017-07-05 18:37:08
239 DebatablySane Bulgarian 16 15 0 48 0 0 0 2017-07-10 15:13:18
240 bretzel15 German 16 20 0 0 1 0 0 2020-04-06 02:49:14
241 engineeringforgood Russian 16 15 0 0 0 0 16 2021-01-22 03:32:35
242 M7md Salahaddin (m7mdsalahaddin) Arabic 16 16 0 1 0 0 0 2024-07-17 18:49:07
243 Bhava Tharini (bhavidanush) Tamil 15 37 0 0 0 0 0 2019-10-09 05:43:11
244 Maro Chr (caprisunglasses) Ch. (sftblw) Greek Korean 14 15 17 0 0 1 0 0 0 2021-08-17 06:53:33 2023-01-25 19:22:34
Zeynep Esen (nezihaesen50) Turkish 14 13 0 0 0 0 0 2020-01-28 07:05:15
245 iamsurajbobade Hindi 14 30 0 0 0 0 0 2018-05-21 11:23:27
246 Faiz Ahamed (faiznewton) Zeynep Esen (nezihaesen50) Tamil Turkish 14 31 13 0 0 0 0 0 2021-05-06 23:06:46 2020-01-28 07:05:15
247 Sanji Vinsmock (mukanzhanbolat4) Russian 14 14 0 0 0 0 0 2020-02-18 12:38:54
Zeeshan Rabbani (Zeera) Hindi 14 25 0 0 0 0 0 2020-09-15 11:32:01
pi hobbes (uwe_silv) Japanese 14 46 0 0 0 0 0 2022-01-15 02:57:14
248 Anastasia Borchuk (al2.borchuk) Russian 14 14 0 0 0 0 0 2020-04-14 13:22:49
249 Fikret Bilici (fikretbilici) Turkish 14 13 0 0 0 0 0 2020-06-21 17:16:11
250 EuiHo Hwang (euiho.hwang) Korean 14 16 0 0 0 1 0 0 2020-06-23 02:40:01
251 Uwe Mönks (schirinowski) Zeeshan Rabbani (Zeera) German Hindi 13 14 12 25 0 0 0 0 0 2021-02-18 04:00:41 2020-09-15 11:32:01
252 Dave (xdave) Faiz Ahamed (faiznewton) Hungarian Tamil 13 14 11 31 0 0 0 0 0 2020-03-02 20:56:50 2021-05-06 23:06:46
253 Ana Kelly Vale (anakvale) Maro Chr (caprisunglasses) Portuguese, Brazilian Greek 13 14 21 17 0 4 0 0 0 2 0 2022-03-30 00:15:37 2021-08-17 06:53:33
254 GiorgioHerbie pi hobbes (uwe_silv) Italian Japanese 13 14 15 46 0 0 0 0 0 14 2022-01-17 17:35:40 2022-01-15 02:57:14
255 Mar Tous (mtousfernandez) Catalan 14 18 0 0 0 0 0 2022-08-16 17:55:28
256 Ferhatt Turkish 14 13 0 3 0 0 0 2022-12-13 12:52:20
257 alchemiker German 14 13 0 0 0 0 0 2024-09-03 10:16:04
258 Nenad Vukotic (vukotic.nenad) Serbian (Cyrillic) 13 13 0 1 2 6 0 2019-01-31 14:29:15
259 soura2 Dave (xdave) Arabic Hungarian 12 13 13 11 0 0 0 0 0 2020-01-13 19:23:47 2020-03-02 20:56:50
260 Uwe Mönks (schirinowski) German 13 12 0 0 0 0 0 2021-02-18 04:00:41
261 Herbie_23 Italian 13 15 0 0 0 0 0 2022-01-17 17:35:40
262 Ana Kelly Vale (anakvale) Portuguese, Brazilian 13 21 0 4 0 0 2 2022-03-30 00:15:37
263 Minsu (cknblue) Korean 13 10 0 1 0 0 0 2022-05-18 00:26:54
264 shreyas (techiespace) Hindi 12 20 0 0 0 0 0 2018-06-10 01:14:26
265 soura2 Arabic 12 13 0 0 0 0 0 2020-01-13 19:23:47
266 Ammar Naif (Ammar_Naif) Arabic 12 12 0 6 0 0 0 2022-01-15 05:16:41
267 Jo Chuang (josephch405) Chinese Traditional 11 24 0 0 0 0 11 2017-06-16 20:21:06
268 Vmrc French 11 12 0 2 0 0 0 2020-11-02 05:35:06
Ammar Naif (Ammar_Naif) Arabic 11 11 0 4 0 0 0 2022-01-15 05:16:41
269 Sonu Sharma (riteetude) Hindi 11 23 0 0 0 0 0 2021-05-30 19:38:00
270 Lucas Depetris (lucasdepetrisd) Spanish; Catalan; Italian; French 11 12 0 12 0 0 0 2023-10-24 21:16:21
271 Mihael Wagner (miha.wagner) Slovenian 10 9 0 7 0 0 0 2017-10-18 18:26:29
272 Anonymous edgy nerd (yamentaad) Arabic 10 13 0 1 0 0 0 2018-05-06 09:23:57
273 Edwin van Rooij (edwinvrooij) Dutch 10 13 0 17 0 0 0 2018-11-05 03:59:10
274 Brian Camacho (bmcamacho) Polish 10 11 0 0 1 1 0 2020-08-03 02:27:28
Mihael Wagner (miha.wagner) Slovenian 10 9 0 7 0 0 0 2017-10-18 18:26:29
Hrant Hakobian (hrastgh1) Armenian 10 9 0 0 0 0 0 2021-08-29 15:22:10
275 sathvic k (sathvictripleseven) Telugu 10 17 0 0 0 0 0 2020-09-11 08:11:32
276 Ahmed Mosaad (ahmed.mosaad2018) Arabic 10 12 0 6 0 0 0 2021-02-03 18:45:43
277 Anonymous edgy nerd (yamentaad) Hrant Hakobian (hrastgh1) Arabic Armenian 10 13 9 0 1 0 0 0 0 2018-05-06 09:23:57 2021-08-29 15:22:10
278 Milan Siebenbürger (lennyd) Czech 10 7 0 1 1 0 0 2022-01-30 07:09:42
279 Zesar Cebrián (Txorrota) Spanish 10 44 0 0 0 0 0 2022-02-09 01:34:32
280 Milan Siebenbürger (lennyd) Слави Велчев (BRO36S) (gg13656) Czech Bulgarian 10 7 11 0 1 9 0 0 0 2022-01-30 07:09:42 2025-01-09 08:47:04
Suhaili Hassan (kucingsyg96) Indonesian 9 10 0 0 0 0 0 2018-06-10 11:55:09
281 Sourire Lucide (sourire_lucide) Russian 9 10 0 0 1 0 0 2018-03-22 01:37:55
282 Martin Vostatek (martinvostatek) Suhaili Hassan (kucingsyg96) Czech Indonesian 9 8 10 0 32 0 2 0 0 0 2019-01-21 13:52:36 2018-06-10 11:55:09
283 Seweryn Piotrowski (Draxxsx) Martin Vostatek (martinvostatek) Polish Czech 9 10 8 0 0 32 19 3 0 0 2020-01-02 09:55:48 2019-01-21 13:52:36
284 Jakob Weickmann (jweickm) Seweryn Piotrowski (Draxxsx) Japanese Polish 8 9 21 10 0 0 0 26 0 0 2021-10-05 11:10:25 2020-01-02 09:55:48
285 omoise French 9 11 0 1 0 0 0 2023-12-26 14:27:17
286 Rex123 Persian 8 8 0 0 0 0 0 2017-07-01 00:47:42
287 Jakob Weickmann (jweickm) Japanese 8 21 0 0 0 0 8 2021-10-05 11:10:25
288 Andrey ZaXeLoN (waragaa) Russian 7 7 0 8 1 0 0 2017-09-18 21:37:42
Konstantin (KZhidovinov) Russian 7 7 0 0 0 0 0 2020-01-29 13:35:12
ftfoi Norwegian 7 6 0 0 0 0 0 2020-04-11 20:42:35
289 Vladimir Pavlychev (vovs03) Russian 7 9 0 0 0 0 0 2017-12-18 02:46:56
290 Felipe Chagas (chagretes) Konstantin (KZhidovinov) Portuguese, Brazilian Russian 7 8 7 0 0 3 0 0 5 0 2022-01-10 12:20:25 2020-01-29 13:35:12
291 pkorove Greek 7 7 0 0 1 0 0 2020-03-07 11:36:12
292 ftfoi Norwegian 7 6 0 0 0 0 0 2020-04-11 20:42:35
293 Андрій Козицький (andriikozytskyi3807) Ukrainian 7 12 0 2 0 0 0 2020-09-26 20:31:56
294 pkorove Felipe Chagas (chagretes) Greek Portuguese, Brazilian 7 7 8 0 0 0 3 0 0 5 2020-03-07 11:36:12 2022-01-10 12:20:25
295 ChloeLiang Tomáš Miklovič (zyppi) Japanese Slovak 6 7 22 7 0 0 1 0 0 3 0 2017-08-08 05:02:59 2022-09-11 15:12:06
296 Sam (SorodonSorodon) German 6 6 0 13 0 0 0 2017-04-14 11:09:27
297 ChloeLiang Japanese 6 22 0 0 1 0 3 2017-08-08 05:02:59
298 닉닉 (seohu9466) Korean 6 14 0 13 0 0 0 2017-10-09 23:08:15
Sarita Cajas (sarayanacajas) Spanish 6 4 0 0 1 0 0 2021-05-14 14:27:59
299 erfan2927 Persian 6 6 0 0 0 0 0 2018-04-09 02:12:44
300 Burak Ceylan (7burakceylan) Turkish 6 6 0 0 0 0 0 2018-05-20 17:24:19
301 andriikozytskyi2018 Sarita Cajas (sarayanacajas) Ukrainian Spanish 5 6 5 4 0 0 0 1 0 0 2017-09-03 05:24:43 2021-05-14 14:27:59
302 Vitor Henrique (vitorhcl) خالد (mkhrafi1999) Portuguese, Brazilian Arabic 5 6 8 3 0 1 6 0 0 0 2022-03-08 20:00:59 2023-06-25 00:36:13
303 Matthias Joly (joly.matt12) French 5 8 0 27 1 0 0 2017-08-28 09:53:59
304 Tomáš Hrabáček (Hrabyyy) andriikozytskyi2018 Czech Ukrainian 5 3 5 0 0 1 0 0 0 2021-05-27 11:58:11 2017-09-03 05:24:43
Guerra Ivaneth (rossanaiva-04) Spanish 5 7 0 0 0 0 0 2019-02-03 16:48:59
305 Дмитрий Хапенков (d.khapenkov) Russian 5 5 0 6 4 0 2 2018-01-06 23:00:43
306 Guerra Ivaneth (rossanaiva-04) Spanish 5 7 0 0 0 0 0 2019-02-03 16:48:59
307 Micaela Pighin (micaelapiighin) Spanish 5 6 0 1 0 0 0 2019-10-09 23:32:42
308 Manuel Tassi (Mannivu) Manuel (Mannivu) Italian 5 6 0 0 0 0 0 2021-01-03 11:00:33
309 Neko123 (emandic11) Tomáš Hrabáček (Hrabyyy) Serbian (Cyrillic) Czech 4 5 4 3 0 57 0 0 2 0 0 2021-04-21 15:33:29 2021-05-27 11:58:11
310 Vitor Henrique (vitorhcl) Portuguese, Brazilian 5 8 0 1 0 0 0 2022-03-08 20:00:59
311 SubhamJena Hindi 5 12 0 3 0 0 0 2023-04-19 11:13:19
312 Lopo Isaac Fernández (rocapata) Spanish 4 3 0 0 0 0 0 2018-09-20 11:46:22
313 Eli Besirov (elibesirov07) Turkish 4 4 0 0 0 0 0 2019-03-25 07:12:34
314 bziuum Polish 4 4 0 0 6 0 0 2020-09-01 09:08:01
315 marmo German 4 4 0 0 0 0 0 2021-01-13 01:16:35
316 bziuum Neko123 (emandic11) Polish Serbian (Cyrillic) 4 4 0 0 57 3 0 0 0 1 2020-09-01 09:08:01 2021-04-21 15:33:29
317 Craig Foobar (craig.foobar) Mo Heydari (Mrheydari) German Dutch 3 4 3 4 0 25 0 0 0 0 2022-02-20 16:55:47 2023-02-21 04:54:49
318 Katarin Srekaravarshan N K (srekaravarshan) Ukrainian Tamil 3 4 3 4 0 0 0 0 0 2022-03-17 14:44:59 2023-04-22 06:08:57
319 Sarath S (CyberShark) Thoum Ptrgnt (thomas.petrignet) Tamil French 3 7 3 0 0 2 0 0 3 0 2020-08-27 22:43:16 2017-09-23 19:25:52
320 carsten_kafke German 3 3 0 43 0 0 3 2017-10-27 13:27:47
321 Vagner Roberto (vagner.trompete) Portuguese, Brazilian 3 3 0 0 0 0 0 2017-12-30 17:54:26
322 Igor Piskun (i_piskun) Ukrainian 3 3 0 0 0 0 0 2018-01-19 15:20:27
Cláudio Bernardo (claudiobernardo.ti) Portuguese, Brazilian 3 4 0 1 0 0 0 2019-01-08 14:41:10
Unnie Here (Carb) Hindi 3 8 0 0 0 0 0 2020-03-18 23:34:35
REMOVED_USER Portuguese, Brazilian 3 4 0 0 0 0 0 2018-11-18 09:02:37
Thoum Ptrgnt (thomas.petrignet) French 3 3 0 2 0 3 0 2017-09-23 19:25:52
Oleg Kogut (kogut_oleg) Ukrainian 3 3 0 0 0 0 0 2018-12-28 14:31:02
carsten_kafke German 3 3 0 43 0 0 3 2017-10-27 13:27:47
Magidxz Arabic 3 3 0 0 0 0 0 2021-01-05 05:02:54
Péter Bernát (bernatp) Hungarian 3 2 0 0 0 0 0 2019-11-30 15:50:33
joabe gabriel (joabegabrielcma1) Portuguese, Brazilian 3 4 0 0 0 0 0 2018-08-21 09:08:59
Gabriel Cavalcante (gabrielc.alves14) Portuguese, Brazilian 3 4 0 0 0 0 0 2018-08-06 22:24:54
Martin Zimdahl (zimdahlmartin) Swedish 3 2 0 0 1 0 3 2018-09-15 04:39:22
atomjani Hungarian 3 3 0 0 0 0 0 2019-01-19 00:49:25
mohammadali barati (mabaraty) Persian 3 3 0 0 0 0 0 2021-07-10 05:54:44
Hiohana Rilary (hiohanarilary) Portuguese, Brazilian 3 4 0 0 0 0 0 2019-07-31 20:42:20
Tejaswini Boppana (Tejaswini) Telugu 3 1 0 0 0 0 0 2021-08-27 23:48:55
323 Andrea Bianchi (andreawhite1597) Italian 3 1 0 1 0 0 0 2018-01-21 17:45:48
324 Ño Bí Tã (pt614553) Gabriel Cavalcante (gabrielc.alves14) Arabic Portuguese, Brazilian 2 3 8 4 0 1 0 0 2 0 0 2021-05-22 20:41:01 2018-08-06 22:24:54
325 Judith Ayala (Azul1612) joabe gabriel (joabegabrielcma1) Spanish Portuguese, Brazilian 2 3 1 4 0 0 0 1 0 0 2021-05-18 17:07:19 2018-08-21 09:08:59
326 Valerij D (vala.dobler) Martin Zimdahl (zimdahlmartin) German Swedish 2 3 2 0 0 0 2 0 0 3 2018-09-22 09:38:27 2018-09-15 04:39:22
327 Balthazar Aubard (Balatzar) REMOVED_USER French Portuguese, Brazilian 2 3 5 4 0 0 1 0 0 0 2017-09-23 01:42:57 2018-11-18 09:02:37
328 Ahmed Bazazo (ahmedbazazo) Oleg Kogut (kogut_oleg) Arabic Ukrainian 2 3 2 3 0 0 0 0 0 2022-02-19 20:11:09 2018-12-28 14:31:02
329 Ali Zaida (alizaeda92) Cláudio Bernardo (claudiobernardo.ti) Arabic Portuguese, Brazilian 2 3 2 4 0 0 1 0 0 0 2019-12-01 11:47:00 2019-01-08 14:41:10
330 FAy FAy (fayfayfay52) atomjani Chinese Traditional Hungarian 2 3 5 3 0 0 0 0 0 2017-10-06 08:53:21 2019-01-19 00:49:25
331 Soroor_SI Hiohana Rilary (hiohanarilary) Persian Portuguese, Brazilian 2 3 2 4 0 0 0 0 0 2018-06-10 06:28:27 2019-07-31 20:42:20
332 chavs1997 Péter Bernát (bernatp) Russian Hungarian 2 3 2 0 9 0 0 0 0 2018-05-18 16:58:19 2019-11-30 15:50:33
333 Naveen jai krishna (njsbpolymer1) Unnie Here (Carb) Tamil Hindi 2 3 5 8 0 0 0 0 0 2020-01-10 14:19:41 2020-03-18 23:34:35
334 omerfarukbas Sarath S (CyberShark) Turkish Tamil 2 3 3 7 0 19 0 2 0 0 0 2017-08-14 16:10:35 2020-08-27 22:43:16
335 Ilyas Fekhar (il47yas) Magidxz Arabic 2 3 2 3 0 0 0 0 0 2018-04-17 22:00:41 2021-01-05 05:02:54
336 Héctor Mañas García (hectodium) mohammadali barati (mabaraty) Catalan Persian 2 3 3 0 0 0 0 0 2021-10-02 20:32:09 2021-07-10 05:54:44
337 Walid Baazia (walidbaazia2005) Tejaswini Boppana (Tejaswini) Arabic Telugu 2 3 1 0 0 0 0 0 2021-01-27 12:47:34 2021-08-27 23:48:55
338 fatemeh s (fargolseifoori3) Craig Foobar (craig.foobar) Persian German 2 3 2 3 0 0 25 0 1 0 0 2019-01-31 12:06:57 2022-02-20 16:55:47
339 hesamiranii (esam.matouri) Katarin Persian Ukrainian 2 3 2 3 0 0 0 0 0 2018-09-22 16:33:36 2022-03-17 14:44:59
340 ayet Arabic 3 3 0 0 0 0 0 2023-08-16 20:18:12
341 REMOVED_USER Ukrainian 2 2 0 0 0 0 0 2017-06-15 12:24:44
342 Alex Stein (diefaust1993) Russian 2 2 0 4 4 0 2 2017-07-13 06:56:17
343 omerfarukbas Turkish 2 3 0 19 2 0 0 2017-08-14 16:10:35
344 Balthazar Aubard (Balatzar) French 2 5 0 0 1 0 0 2017-09-23 01:42:57
345 FAy FAy (fayfayfay52) Chinese Traditional 2 5 0 0 0 0 0 2017-10-06 08:53:21
346 Ilyas Fekhar (il47yas) Arabic 2 2 0 0 0 0 0 2018-04-17 22:00:41
347 amei Portuguese, Brazilian 2 2 0 0 0 0 0 2018-04-19 19:42:28
348 أم محمد تقي (souadboudia19) Jimmy Young (Jimmyyoung) Arabic Chinese Traditional 2 2 4 0 0 0 0 0 2 2020-06-13 15:24:17 2018-04-22 04:00:19
349 LNDDYL chavs1997 Chinese Traditional Russian 2 4 2 0 0 9 0 0 2 0 2018-04-22 04:00:19 2018-05-18 16:58:19
350 조화정 (yunjoo337) Soroor_SI Korean Persian 2 2 0 0 0 0 0 2019-06-16 22:25:31 2018-06-10 06:28:27
351 Sidali Aymen (sidaliaymen950) Valerij D (vala.dobler) Arabic German 2 2 0 0 0 0 0 2022-01-31 18:50:59 2018-09-22 09:38:27
352 hesamiranii (esam.matouri) Persian 2 2 0 0 0 0 0 2018-09-22 16:33:36
353 fatemeh s (fargolseifoori3) Persian 2 2 0 0 0 0 0 2019-01-31 12:06:57
354 Danial Agh (danialagh) Persian 2 3 0 0 0 0 0 2019-03-30 13:24:16
355 조화정 (yunjoo337) Korean 2 2 0 0 0 0 0 2019-06-16 22:25:31
356 Ali Zaida (alizaeda92) Arabic 2 2 0 0 0 0 0 2019-12-01 11:47:00
357 Naveen jai krishna (njsbpolymer1) Tamil 2 5 0 0 1 0 0 2020-01-10 14:19:41
358 أم محمد تقي (souadboudia19) Arabic 2 2 0 0 0 0 0 2020-06-13 15:24:17
359 Walid Baazia (walidbaazia2005) Arabic 2 1 0 0 0 0 0 2021-01-27 12:47:34
360 Judith Ayala (Azul1612) Spanish 2 1 0 0 0 1 0 2021-05-18 17:07:19
361 Ño Bí Tã (pt614553) Arabic 2 8 0 1 0 2 0 2021-05-22 20:41:01
362 Héctor Mañas García (hectodium) Catalan 2 3 0 0 0 0 0 2021-10-02 20:32:09
363 Sidali Aymen (sidaliaymen950) Arabic 2 2 0 0 0 0 0 2022-01-31 18:50:59
364 Ahmed Bazazo (ahmedbazazo) Arabic 2 2 0 0 0 0 0 2022-02-19 20:11:09
365 HypemanKEK (rocasta.dodvi) Russian 2 2 0 0 0 0 0 2023-01-13 03:45:06
366 Gmas (gustmaes1) Dutch 2 2 0 0 0 0 0 2023-01-26 13:52:54
367 Катерина Ховалкина (katerina959) Russian 2 2 0 1 0 0 0 2023-05-18 14:50:30
368 Pratheba Devanathan (devprath05) Tamil 2 2 0 0 1 0 0 2023-06-05 12:35:45
369 Gordon James Campbell (gordonjamescampbell) Catalan 2 2 0 0 0 0 0 2023-06-23 23:23:46
370 Suren Airyanam (suren.airyanam) Persian 2 2 0 0 0 0 0 2023-10-21 18:01:41
371 axq German 2 1 0 1 0 0 0 2024-02-29 17:14:13
372 Hades Mori (Hades_Mori) Ukrainian 2 2 0 0 0 0 0 2024-07-03 07:14:58
373 iSoron2 Portuguese, Brazilian 1 1 0 0 0 0 0 2017-03-18 17:56:29
374 Anton (tT0NG) Chinese Traditional 1 2 0 0 0 0 1 2017-07-06 14:18:39
375 Luca Gori (grolcu) axd Italian Spanish 1 2 1 0 0 15 0 1 0 0 2020-09-26 23:26:15 2017-09-12 05:48:51
axd Spanish 1 1 0 15 0 0 0 2017-09-12 05:48:51
REMOVED_USER Russian 1 2 0 6 1 0 1 2019-12-26 05:37:01
jonesses German 1 1 0 1 0 0 1 2021-01-01 08:03:18
Alan Jeon (skyisle) Korean 1 2 0 8 0 0 0 2018-01-09 10:46:00
Maria Fefelova (mashafefel) Russian 1 1 0 0 0 0 0 2019-05-18 02:03:56
Patrick Pimenta (trickap1) Portuguese, Brazilian 1 1 0 0 0 0 0 2018-12-01 14:31:21
박찌 (perpact20) Korean 1 1 0 0 0 0 0 2018-02-10 10:11:44
Kan Black (kanblack.va) Vietnamese 1 2 0 0 0 1 0 2019-01-15 03:50:10
Anastasiia Bondarenko (nastasya.bondarenko.97) Russian 1 1 0 0 0 0 0 2019-06-07 17:43:08
376 Wibi Cahyo (wbcahyoh) Indonesian 1 3 0 0 0 0 0 2017-12-14 06:35:58
377 sanyoniket Alan Jeon (skyisle) Korean 0 1 0 2 0 0 8 0 0 0 2019-07-23 12:58:40 2018-01-09 10:46:00
378 Sri Harsha Bhogi (sriharshabhogi) 박찌 (perpact20) Korean 0 1 0 1 0 0 0 0 0 2018-09-02 05:31:53 2018-02-10 10:11:44
379 Irsgram Patrick Pimenta (trickap1) Russian Portuguese, Brazilian 0 1 0 1 0 1 0 0 0 0 2019-09-30 16:42:20 2018-12-01 14:31:21
380 Baran Özavcı (n2141n) Kan Black (kanblack.va) Turkish Vietnamese 0 1 0 2 0 1 0 0 0 1 0 2022-02-26 04:32:51 2019-01-15 03:50:10
381 Masataka Yakura (myakura) Maria Fefelova (mashafefel) Japanese Russian 0 1 0 1 0 1 0 0 0 0 2021-09-03 22:10:36 2019-05-18 02:03:56
382 ava_rfie Anastasiia Bondarenko (nastasya.bondarenko.97) Persian Russian 0 1 0 1 0 1 0 0 0 0 2019-06-09 16:19:24 2019-06-07 17:43:08
383 T-v-Gerwen REMOVED_USER Dutch Russian 0 1 0 2 0 47 6 0 1 0 0 1 2018-03-02 10:26:33 2019-12-26 05:37:01
384 George Merkulov (george142.emarket) Luca Gori (grolcu) Russian Italian 0 1 0 2 0 11 0 0 0 0 2019-06-09 19:47:02 2020-09-26 23:26:15
385 philfr49 jonesses French German 0 1 0 1 0 2 1 0 0 0 1 2018-09-03 14:20:32 2021-01-01 08:03:18
386 عبد الناصر سعيد الثبيتي (asaeed) monir s (ms.alam) Persian 0 1 0 1 0 0 1 0 0 0 2018-03-13 02:09:35 2022-05-23 06:34:00
387 Thomas Orlita (Thomas995) Daniel Luque (LuqueDaniel) Czech Spanish 0 1 0 1 0 1 0 0 0 0 2017-12-24 04:08:27 2022-06-30 20:37:07
388 Edmunds Edmundam (edmundam) Liboide Spanish 0 1 0 1 0 0 0 0 0 2020-06-01 14:18:18 2022-11-03 23:57:45
389 Elmo (oberknecht) K RITE (kriteshojha5) Hindi 0 1 0 1 0 0 1 0 0 0 2020-04-16 08:45:50 2024-08-14 17:28:55
390 Равиль Мифтахов (ravilmif47) Angelos (angelos1993) Russian Arabic 0 1 0 1 0 1 0 0 0 0 2019-08-12 21:58:30 2024-11-20 07:38:18
391 Manny Farsangy (manifarsangi) Bora Atıcı (Brtc) Persian Turkish 0 1 0 2 0 12 0 0 0 0 2021-08-10 05:32:28 2025-03-07 20:33:19
Samuel Przeździęk (samek22) Polish 0 0 0 1 0 0 0 2021-08-01 00:49:01
Saiprasath B (Saiprasath) 0 0 0 0 0 0 0 2021-07-11 11:10:41
REMOVED_USER 0 0 0 0 0 0 0 2018-08-24 00:17:43
REMOVED_USER 0 0 0 0 0 0 0 2020-02-01 03:47:48
Arjun K. (arjunkdot) 0 0 0 0 0 0 0 2020-09-20 11:16:18
EwanB 0 0 0 0 0 0 0 2019-11-19 10:04:38
shuvo786 0 0 0 0 0 0 0 2019-11-13 00:18:12
Pro AAA (pro1010) Arabic 0 0 0 1 0 0 0 2022-02-14 03:32:44
manu (manuL96) 0 0 0 0 0 0 0 2022-05-06 23:34:55
Rivo Zängov (Eraser) 0 0 0 0 0 0 0 2020-10-13 04:38:26
ashik8113 0 0 0 0 0 0 0 2022-04-13 11:58:26
deepbird 0 0 0 0 0 0 0 2022-04-11 03:21:05
REMOVED_USER 0 0 0 0 0 0 0 2018-10-27 15:34:36
Elham1361 0 0 0 0 0 0 0 2018-10-27 12:01:06
Ahnaf Tajwar (atn4404) 0 0 0 0 0 0 0 2018-10-16 11:13:30
martyaberger 0 0 0 0 0 0 0 2019-01-01 18:48:08
AsadullahIlyas 0 0 0 0 0 0 0 2019-01-04 06:14:15
akmal shafiq (mohdakmalshafiq) 0 0 0 0 0 0 0 2021-11-01 01:04:50
Sylwuskak (sylwuskak) Polish 0 0 0 1 0 0 0 2022-01-25 04:19:53
Yunsu Kim (yunsukim86) Korean 0 0 0 2 0 0 0 2022-01-14 06:33:43
Pumpith Ungsupanit (pumpithu) 0 0 0 0 0 0 0 2019-01-19 23:47:57
Nat Fomicheva (natac) Russian 0 0 0 3 0 0 0 2019-01-25 14:35:02
HemanthMeda Telugu 0 0 0 4 0 0 0 2021-12-01 14:02:14
darkkingredian (rediancool) 0 0 0 0 0 0 0 2021-07-27 16:04:32
catemlitten Japanese 0 0 0 1 0 0 0 2021-11-17 15:06:02
Said Tahsin Dane (tasomaniac) 0 0 0 0 0 0 0 2021-09-25 05:31:01
Matus Zdansky (matuszdansky) 0 0 0 0 0 0 0 2019-10-20 13:52:24
mdrobulis 0 0 0 0 0 0 0 2018-05-24 01:40:42
valney.faria Portuguese, Brazilian 0 0 0 1 0 0 0 2020-02-02 14:45:02
Petros Bleyan (coolbleyan) Russian 0 0 0 14 0 0 0 2017-08-18 18:37:18
Карлен Шаухаев (KarlenShaukhaev) 0 0 0 0 0 0 0 2020-04-27 08:53:49
Shuvashish Sahoo (shuvashish76) 0 0 0 0 0 0 0 2020-09-17 09:10:09
REMOVED_USER 0 0 0 0 0 0 0 2018-01-05 16:56:12
Dagna Q (dagnaq) 0 0 0 0 0 0 0 2017-08-06 01:42:52
Sandhu564. 0 0 0 0 0 0 0 2020-12-14 01:27:45
AhmedDz Arabic 0 0 0 1 0 0 0 2017-12-31 10:12:31
Quentin Hibon (hiq) 0 0 0 0 0 0 0 2021-02-07 16:39:31
Ahmed Nazir (ahmednazir333) 0 0 0 0 0 0 0 2018-05-06 12:10:27
박인호 (wphestiraid) Korean 0 0 0 2 0 0 0 2018-01-05 00:33:14
Raulbertassi 0 0 0 0 0 0 0 2018-01-07 17:23:18
Javid IRAN (twitteriran98) Persian 0 0 0 1 0 0 0 2017-11-25 16:47:25
Wellington Ribeiro (wellington.rib) 0 0 0 0 0 0 0 2017-11-16 07:32:25
dimateos 0 0 0 0 0 0 0 2021-01-10 06:29:52
Balaji Jayaraman (jkbalaji1103) 0 0 0 0 0 0 0 2017-10-30 22:12:27
reza golestanzadeh (reza.golestanzadeh) Persian 0 0 0 1 0 0 0 2020-10-21 12:07:20
Muhammet Furkan ALMACI (furkan.almaci) Turkish 0 0 0 1 0 0 0 2017-10-29 13:44:56
dongchen.yue German 0 0 0 4 0 0 0 2020-09-12 15:05:59
Алтынбек Наурызғали (altinbeknaurizgali) Russian 0 0 0 1 0 0 0 2020-08-12 13:03:49
rooban23 0 0 0 0 0 0 0 2020-09-15 11:49:14
NairaDNV Spanish 0 0 0 9 0 0 0 2018-01-05 19:10:33
Katherine Alexandra Flórez Ramírez (katherine.florez12) Spanish 0 0 0 46 0 0 0 2018-01-20 02:18:32
Itch 0 0 0 0 0 0 0 2017-10-16 09:18:42
Yasin Okumus (lacivert) Turkish 0 0 0 1 0 0 0 2018-02-07 04:13:51
Eduard Boboc (edi.boboc33) Romanian 0 0 0 4 0 0 0 2019-12-16 09:08:39
Hayder21 0 0 0 0 0 0 0 2019-12-31 10:56:24
Eliška Roubalová (roubaeli) Czech 0 0 0 6 0 0 0 2019-12-31 12:47:29
Fazy1380 0 0 0 0 0 0 0 2021-04-10 11:02:53
Arttu Ylhävuori (arttu.ylhavuori) 0 0 0 0 0 0 0 2019-07-24 15:03:42
392 EmanAmini 0 0 0 0 0 0 0 2017-03-31 13:27:43
393 AnggaRifandi 0 0 0 0 0 0 0 2017-03-31 19:28:35
394 Lori Amico (lavodkaclyde2323) Italian 0 0 0 1 0 0 0 2017-04-09 10:08:13
395 Florian Stuhlmann (stuhlmann) German 0 0 0 10 0 0 0 2017-04-15 04:04:00
396 Kamalakannan 0 0 0 0 0 0 0 2017-05-14 11:40:23
farbod66 Persian 0 0 0 1 0 0 0 2018-01-20 11:04:23
vi ve (VimalV) 0 0 0 0 0 0 0 2021-02-08 02:35:45
397 Éjbãss Übbeî (littlebittlebottle) Norwegian 0 0 0 152 0 0 0 2017-07-05 21:12:02
398 LeMeD (LeMeS) Dagna Q (dagnaq) French 0 0 0 2 0 0 0 0 2021-02-06 15:35:00 2017-08-06 01:42:52
399 BongTran Petros Bleyan (coolbleyan) Vietnamese Russian 0 0 0 2 14 0 0 0 2018-04-24 05:16:07 2017-08-18 18:37:18
400 REMOVED_USER Itch Czech 0 0 0 18 0 0 0 0 2018-03-27 06:19:52 2017-10-16 09:18:42
401 mushin Muhammet Furkan ALMACI (furkan.almaci) Turkish 0 0 0 0 1 0 0 0 2020-02-02 04:08:05 2017-10-29 13:44:56
402 Mateusz Teteruk (mttet) Balaji Jayaraman (jkbalaji1103) Polish 0 0 0 1 0 0 0 0 2021-01-23 13:09:59 2017-10-30 22:12:27
403 Sarah BCNN (fsarahboucenna) Wellington Ribeiro (wellington.rib) French 0 0 0 16 0 0 0 0 2018-02-11 11:07:36 2017-11-16 07:32:25
404 Javid IRAN (twitteriran98) Persian 0 0 0 1 0 0 0 2017-11-25 16:47:25
405 REMOVED_USER Czech 0 0 0 1 0 0 0 2017-12-24 04:08:27
406 AhmedDz Arabic 0 0 0 1 0 0 0 2017-12-31 10:12:31
407 박인호 (wphestiraid) Korean 0 0 0 2 0 0 0 2018-01-05 00:33:14
408 REMOVED_USER 0 0 0 0 0 0 0 2018-01-05 16:56:12
409 NairaDNV Spanish 0 0 0 9 0 0 0 2018-01-05 19:10:33
410 Raulbertassi 0 0 0 0 0 0 0 2018-01-07 17:23:18
411 Katherine Alexandra Flórez Ramírez (katherine.florez12) Spanish 0 0 0 46 0 0 0 2018-01-20 02:18:32
412 farbod66 Persian 0 0 0 1 0 0 0 2018-01-20 11:04:23
413 droidahmed Arabic 0 0 0 7 0 0 0 2018-01-31 02:18:49
414 Yasin Okumus (lacivert) Turkish 0 0 0 1 0 0 0 2018-02-07 04:13:51
415 Sarah BCNN (fsarahboucenna) French 0 0 0 16 0 0 0 2018-02-11 11:07:36
416 T-v-Gerwen Dutch 0 0 0 47 0 0 0 2018-03-02 10:26:33
417 عبد الناصر سعيد الثبيتي (asaeed) 0 0 0 0 0 0 0 2018-03-13 02:09:35
418 REMOVED_USER Czech 0 0 0 18 0 0 0 2018-03-27 06:19:52
419 BongTran Vietnamese 0 0 0 2 0 0 0 2018-04-24 05:16:07
420 Ahmed Nazir (ahmednazir333) 0 0 0 0 0 0 0 2018-05-06 12:10:27
421 mdrobulis 0 0 0 0 0 0 0 2018-05-24 01:40:42
422 REMOVED_USER 0 0 0 0 0 0 0 2018-08-24 00:17:43
423 Sri Harsha Bhogi (sriharshabhogi) 0 0 0 0 0 0 0 2018-09-02 05:31:53
424 philfr49 French 0 0 0 2 0 0 0 2018-09-03 14:20:32
425 Ahnaf Tajwar (atn4404) 0 0 0 0 0 0 0 2018-10-16 11:13:30
426 Elham1361 0 0 0 0 0 0 0 2018-10-27 12:01:06
427 REMOVED_USER 0 0 0 0 0 0 0 2018-10-27 15:34:36
428 Никита Карамов (nikita.karamoff) Russian 0 0 0 10 0 0 0 2018-10-29 03:57:21
429 martyaberger 0 0 0 0 0 0 0 2019-01-01 18:48:08
430 AsadullahIlyas 0 0 0 0 0 0 0 2019-01-04 06:14:15
431 Pumpith Ungsupanit (pumpithu) 0 0 0 0 0 0 0 2019-01-19 23:47:57
432 Nat Fomicheva (natac) Russian 0 0 0 3 0 0 0 2019-01-25 14:35:02
433 ava_rfie Persian 0 0 0 1 0 0 0 2019-06-09 16:19:24
434 George Merkulov (george142.emarket) Russian 0 0 0 11 0 0 0 2019-06-09 19:47:02
435 sanyoniket 0 0 0 0 0 0 0 2019-07-23 12:58:40
436 Arttu Ylhävuori (arttu.ylhavuori) 0 0 0 0 0 0 0 2019-07-24 15:03:42
437 Равиль Мифтахов (ravilmif47) Russian 0 0 0 1 0 0 0 2019-08-12 21:58:30
438 Irsgram Russian 0 0 0 1 0 0 0 2019-09-30 16:42:20
439 Matus Zdansky (matuszdansky) 0 0 0 0 0 0 0 2019-10-20 13:52:24
440 shuvo786 0 0 0 0 0 0 0 2019-11-13 00:18:12
441 EwanB 0 0 0 0 0 0 0 2019-11-19 10:04:38
442 Eduard Boboc (edi.boboc33) Romanian 0 0 0 4 0 0 0 2019-12-16 09:08:39
443 Hayder21 0 0 0 0 0 0 0 2019-12-31 10:56:24
444 Eliška Roubalová (roubaeli) Czech 0 0 0 6 0 0 0 2019-12-31 12:47:29
445 REMOVED_USER 0 0 0 0 0 0 0 2020-02-01 03:47:48
446 mushin 0 0 0 0 0 0 0 2020-02-02 04:08:05
447 valney.faria Portuguese, Brazilian 0 0 0 1 0 0 0 2020-02-02 14:45:02
448 Elmo (oberknecht) 0 0 0 0 0 0 0 2020-04-16 08:45:50
449 Карлен Шаухаев (KarlenShaukhaev) 0 0 0 0 0 0 0 2020-04-27 08:53:49
450 Edmunds Edmundam (edmundam) 0 0 0 0 0 0 0 2020-06-01 14:18:18
451 Алтынбек Наурызғали (altinbeknaurizgali) Russian 0 0 0 1 0 0 0 2020-08-12 13:03:49
452 dongchen.yue German 0 0 0 4 0 0 0 2020-09-12 15:05:59
453 rooban23 0 0 0 0 0 0 0 2020-09-15 11:49:14
454 REMOVED_USER 0 0 0 0 0 0 0 2020-09-17 09:10:09
455 Arjun K. (arjunkdot) 0 0 0 0 0 0 0 2020-09-20 11:16:18
456 Rivo Zängov (Eraser) 0 0 0 0 0 0 0 2020-10-13 04:38:26
457 reza golestanzadeh (reza.golestanzadeh) Persian 0 0 0 1 0 0 0 2020-10-21 12:07:20
458 Sandhu564. 0 0 0 0 0 0 0 2020-12-14 01:27:45
459 dimateos 0 0 0 0 0 0 0 2021-01-10 06:29:52
460 Mateusz Teteruk (mttet) Polish 0 0 0 1 0 0 0 2021-01-23 13:09:59
461 LeMeD (LeMeS) French 0 0 0 2 0 0 0 2021-02-06 15:35:00
462 Quentin Hibon (hiq) 0 0 0 0 0 0 0 2021-02-07 16:39:31
463 vi ve (VimalV) 0 0 0 0 0 0 0 2021-02-08 02:35:45
464 Fazy1380 0 0 0 0 0 0 0 2021-04-10 11:02:53
465 Saiprasath B (Saiprasath) 0 0 0 0 0 0 0 2021-07-11 11:10:41
466 darkkingredian (rediancool) 0 0 0 0 0 0 0 2021-07-27 16:04:32
467 Samuel Przeździęk (samek22) Polish 0 0 0 1 0 0 0 2021-08-01 00:49:01
468 Manny Farsangy (manifarsangi) Persian 0 0 0 12 0 0 0 2021-08-10 05:32:28
469 Masataka Yakura (myakura) Japanese 0 0 0 1 0 0 0 2021-09-03 22:10:36
470 Said Tahsin Dane (tasomaniac) 0 0 0 0 0 0 0 2021-09-25 05:31:01
471 akmal shafiq (mohdakmalshafiq) 0 0 0 0 0 0 0 2021-11-01 01:04:50
472 catemlitten Japanese 0 0 0 1 0 0 0 2021-11-17 15:06:02
473 HemanthMeda Telugu 0 0 0 4 0 0 0 2021-12-01 14:02:14
474 Yunsu Kim (yunsukim86) Korean 0 0 0 2 0 0 0 2022-01-14 06:33:43
475 Sylwuskak (sylwuskak) Polish 0 0 0 1 0 0 0 2022-01-25 04:19:53
476 Pro AAA (pro1010) Arabic 0 0 0 1 0 0 0 2022-02-14 03:32:44
477 Baran Özavcı (n2141n) Turkish 0 0 0 1 0 0 0 2022-02-26 04:32:51
478 deepbird 0 0 0 0 0 0 0 2022-04-11 03:21:05
479 ashik8113 0 0 0 0 0 0 0 2022-04-13 11:58:26
480 manu (manuL96) 0 0 0 0 0 0 0 2022-05-06 23:34:55
481 Agnel (agnelwaghela) 0 0 0 0 0 0 0 2022-06-19 10:32:33
482 Ruslan Zaynetdinov (theRuslan) Russian 0 0 0 6 0 0 0 2022-07-06 10:48:31
483 Marcel (flaced) German 0 0 0 1 0 0 0 2022-08-19 15:19:26
484 pixx1 German 0 0 0 6 0 0 0 2022-08-22 00:38:13
485 Onder Nuray (ondernuray) 0 0 0 0 0 0 0 2022-08-30 08:16:27
486 Md Faridul Islam (mdfaridulislam509) 0 0 0 0 0 0 0 2022-09-04 06:25:20
487 Felone 0 0 0 0 0 0 0 2022-09-10 08:04:02
488 Sawwwwwplan 0 0 0 0 0 0 0 2022-09-10 11:35:14
489 Fatima (fatima.a) Arabic 0 0 0 1 0 0 0 2022-09-20 09:48:25
490 DomiAlt 0 0 0 0 0 0 0 2022-10-02 15:44:26
491 Erwindly Polish 0 0 0 1 0 0 0 2022-11-01 04:12:58
492 Deniz Çelik (DenizCelik) 0 0 0 0 0 0 0 2022-11-09 02:13:11
493 Watashiwanilli 0 0 0 0 0 0 0 2022-11-14 10:12:21
494 Maxence LIGAN (Daddy_Caramel) 0 0 0 0 0 0 0 2022-12-23 04:43:30
495 wstroobandt Dutch 0 0 0 1 0 0 0 2023-01-03 17:52:42
496 ニキホロブ蒼井 (abhigyahazra) 0 0 0 0 0 0 0 2023-01-08 21:37:53
497 Afrim Kamberi (afrimkamberi) 0 0 0 0 0 0 0 2023-01-17 05:20:06
498 ViacheslavLabs Ukrainian 0 0 0 5 0 0 0 2023-01-21 15:34:40
499 Basta 0 0 0 0 0 0 0 2023-03-04 16:13:57
500 raselh 0 0 0 0 0 0 0 2023-03-15 03:33:21
501 Adrian Miozga (AdrianMiozga) Polish 0 0 0 13 0 0 0 2023-03-25 17:00:53
502 Atlas Steel (atlas.steel.erbil) 0 0 0 0 0 0 0 2023-05-16 05:23:32
503 Sathyakumar Ps (sathyakumar63) 0 0 0 0 0 0 0 2023-05-24 11:44:23
504 Abdul nafih (nafih_zain_) 0 0 0 0 0 0 0 2023-05-25 06:24:31
505 Bernhard (bernikr) German 0 0 0 1 0 0 0 2023-06-12 11:18:18
506 Anna Boda (annaboda08) Hungarian 0 0 0 1 0 0 0 2023-07-03 13:28:12
507 Rubén CH (chruben45) Spanish 0 0 0 1 0 0 0 2023-07-24 12:39:51
508 Vinicius (exteraDev) 0 0 0 0 0 0 0 2023-08-08 15:47:45
509 mugdad alhammad (alhammad5057) 0 0 0 0 0 0 0 2023-08-13 22:36:01
510 Arthur Waldes (arthurwaldes) 0 0 0 0 0 0 0 2023-08-22 15:38:12
511 Mahmoud Hatem (mahmoudhatem) Arabic 0 0 0 1 0 0 0 2023-09-12 05:12:34
512 Jacques Francky Salomon (jacquesfranckysalomon) 0 0 0 0 0 0 0 2023-10-14 20:55:30
513 Mohammad Hashem (hashemchattogram) 0 0 0 0 0 0 0 2023-10-27 02:15:39
514 Aylinddd Persian 0 0 0 1 0 0 0 2023-11-07 22:50:37
515 Dinock German 0 0 0 1 0 0 0 2023-11-10 07:08:23
516 zelfoxx German 0 0 0 12 0 0 0 2023-11-22 11:11:44
517 REMOVED_USER 0 0 0 0 0 0 0 2023-11-28 17:42:55
518 Dennis Li (Dennis_Li) Chinese Simplified 0 0 0 1 0 0 0 2023-12-24 21:12:43
519 REMOVED_USER Russian 0 0 0 5 0 0 0 2024-01-01 17:15:06
520 Daniill l (daniill) 0 0 0 0 0 0 0 2024-01-12 02:42:52
521 NONE NAME (RagnarGraves) Spanish 0 0 0 1 0 0 0 2024-02-18 01:39:39
522 lu21232512 0 0 0 0 0 0 0 2024-04-15 12:40:05
523 Oscariño (oscarinhooo) 0 0 0 0 0 0 0 2024-07-07 08:47:25
524 Vladimir Sveshnikov (proloxy) Russian 0 0 0 6 0 0 0 2024-07-12 03:27:39
525 L0f3n Swedish 0 0 0 2 0 0 0 2024-08-06 17:13:50
526 Christer Fletcher (chrfle) Swedish 0 0 0 2 0 0 0 2024-08-15 04:15:49
527 Moaid alzawy (dodoalzawy200) Arabic 0 0 0 1 0 0 0 2024-09-18 12:17:31
528 Eduardo Ferreira (eduu) 0 0 0 0 0 0 0 2024-10-27 19:09:20
529 عبد الملك بلكم (aboodpvp555) Arabic 0 0 0 1 0 0 0 2024-12-12 02:42:14
530 4Kio Russian 0 0 0 1 0 0 0 2024-12-12 12:31:25
531 رودينه (rwdynh874) Arabic 0 0 0 1 0 0 0 2024-12-24 18:31:33
532 zahra ghasemi (z.ghasemizahra) Persian 0 0 0 1 0 0 0 2024-12-29 04:36:27
533 Mustafa Işıksız (mustafalordon27) Turkish 0 0 0 1 0 0 0 2025-01-15 13:52:32
534 Ahlem Ben (ahlemben1513) Arabic 0 0 0 1 0 0 0 2025-02-12 11:09:57
535 Francisco Parra (Frn_7) Spanish 0 0 0 1 0 0 0 2025-02-18 22:57:05
536 mizumoto (yuta-mizumoto) Japanese 0 0 0 2 0 0 0 2025-03-03 18:35:56

View File

@@ -18,27 +18,36 @@
*/
plugins {
id("com.github.triplet.play") version "3.7.0"
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.kapt")
id("org.jetbrains.kotlin.android.extensions")
id("org.jlleitschuh.gradle.ktlint")
alias(libs.plugins.agp)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.ktlint.plugin)
}
tasks.compileLint {
dependsOn("updateTranslators")
}
android {
/*
Added on top of kotlinOptions to work around this issue:
https://youtrack.jetbrains.com/issue/KTIJ-24311/task-current-target-is-17-and-kaptGenerateStubsProductionDebugKotlin-task-current-target-is-1.8-jvm-target-compatibility-should#focus=Comments-27-6798448.0-0
Updating gradle might fix this, so try again in the future to remove this and run:
./gradlew --rerun-tasks :uhabits-android:kaptGenerateStubsReleaseKotlin
If this doesn't produce any warning, try to remove it.
*/
kotlin {
jvmToolchain(11)
}
compileSdk = 32
android {
namespace = "org.isoron.uhabits"
compileSdk = 36
defaultConfig {
versionCode = 20101
versionName = "2.1.1"
versionCode = 20300
versionName = "2.3.0"
minSdk = 28
targetSdk = 31
targetSdk = 36
applicationId = "org.isoron.uhabits"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -55,7 +64,7 @@ android {
}
buildTypes {
getByName("release") {
release {
isMinifyEnabled = true
proguardFiles(getDefaultProguardFile("proguard-android.txt"), "proguard-rules.txt")
if (signingConfigs.findByName("release") != null) {
@@ -63,71 +72,45 @@ android {
}
}
getByName("debug") {
isTestCoverageEnabled = true
debug {
enableUnitTestCoverage = true
}
}
compileOptions {
isCoreLibraryDesugaringEnabled = true
targetCompatibility(JavaVersion.VERSION_1_8)
sourceCompatibility(JavaVersion.VERSION_1_8)
targetCompatibility(JavaVersion.VERSION_11)
sourceCompatibility(JavaVersion.VERSION_11)
}
buildFeatures {
viewBinding = true
}
kotlinOptions.jvmTarget = JavaVersion.VERSION_11.toString()
buildFeatures.viewBinding = true
lint.abortOnError = false
}
dependencies {
val daggerVersion = "2.44.2"
val kotlinVersion = "1.7.21"
val kxCoroutinesVersion = "1.6.4"
val ktorVersion = "1.6.8"
val espressoVersion = "3.5.0"
androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion")
androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion")
androidTestImplementation("com.google.dagger:dagger:$daggerVersion")
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.5.0")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
androidTestImplementation("androidx.test:rules:1.5.0")
androidTestImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
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")
implementation("com.google.code.findbugs:jsr305:3.0.2")
implementation("com.google.dagger:dagger:$daggerVersion")
implementation("com.google.guava:guava:31.1-android")
implementation("io.ktor:ktor-client-android:$ktorVersion")
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-jackson:$ktorVersion")
implementation("io.ktor:ktor-client-json:$ktorVersion")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kxCoroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kxCoroutinesVersion")
implementation("androidx.appcompat:appcompat:1.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.8.0")
implementation("com.opencsv:opencsv:5.7.1")
compileOnly(libs.jsr250.api)
coreLibraryDesugaring(libs.desugar.jdk.libs)
implementation(libs.appIntro)
implementation(libs.jsr305)
implementation(libs.dagger)
implementation(libs.guava)
implementation(libs.ktor.client.android)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.jackson)
implementation(libs.ktor.client.json)
implementation(libs.kotlin.stdlib.jdk8)
implementation(libs.kotlinx.coroutines.android)
implementation(libs.kotlinx.coroutines.core)
implementation(libs.appcompat)
implementation(libs.legacy.preference.v14)
implementation(libs.legacy.support.v4)
implementation(libs.material)
implementation(libs.opencsv)
implementation(libs.konfetti.xml)
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")
}
ksp(libs.dagger.compiler)
kapt {
correctErrorTypes = true
}
play {
serviceAccountCredentials.set(file("../.secret/gcp-key.json"))
track.set("alpha")
androidTestImplementation(libs.bundles.androidTest)
testImplementation(libs.bundles.test)
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@@ -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() {

View File

@@ -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

View File

@@ -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 {

View File

@@ -20,7 +20,6 @@ package org.isoron.uhabits.acceptance.steps
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Build.VERSION_CODES
import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView
import androidx.test.espresso.Espresso
@@ -33,11 +32,11 @@ import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.uiautomator.By
import androidx.test.uiautomator.UiSelector
import androidx.test.uiautomator.Until
import junit.framework.Assert.assertTrue
import org.hamcrest.CoreMatchers
import org.isoron.uhabits.BaseUserInterfaceTest
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.habits.list.ListHabitsActivity
import org.junit.Assert.assertTrue
object CommonSteps : BaseUserInterfaceTest() {
fun pressBack() {
@@ -133,7 +132,7 @@ object CommonSteps : BaseUserInterfaceTest() {
}
@Throws(Exception::class)
fun verifyOpensWebsite(url: String?) {
fun verifyOpensWebsite(url: String) {
var browserPkg = "org.chromium.webview_shell"
if (SDK_INT <= Build.VERSION_CODES.M) {
browserPkg = "com.android.browser"
@@ -148,15 +147,19 @@ object CommonSteps : BaseUserInterfaceTest() {
Screen.LIST_HABITS ->
Espresso.onView(ViewMatchers.withClassName(CoreMatchers.endsWith("ListHabitsRootView")))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Screen.SHOW_HABIT ->
Espresso.onView(ViewMatchers.withId(R.id.subtitleCard))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Screen.EDIT_HABIT ->
Espresso.onView(ViewMatchers.withId(R.id.questionInput))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
Screen.SELECT_HABIT_TYPE ->
Espresso.onView(ViewMatchers.withText(R.string.yes_or_no_example))
.check(ViewAssertions.matches(ViewMatchers.isDisplayed()))
else -> throw IllegalStateException()
}
}

View File

@@ -21,9 +21,9 @@ package org.isoron.uhabits.acceptance.steps
import android.os.Build.VERSION.SDK_INT
import androidx.test.uiautomator.UiScrollable
import androidx.test.uiautomator.UiSelector
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.isoron.uhabits.BaseUserInterfaceTest
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
object WidgetSteps {
@Throws(Exception::class)

View File

@@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.activities.common.views
import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest
@@ -52,7 +53,8 @@ class FrequencyChartTest : BaseViewTest() {
@Test
@Throws(Throwable::class)
fun testRender_withDataOffset() {
view.onScroll(null, null, -dpToPixels(150), 0f)
val e = MotionEvent.obtain(0, 0, 0, 0f, 0f, 0)
view.onScroll(e, e, -dpToPixels(150), 0f)
view.invalidate()
assertRenders(view, BASE_PATH + "renderDataOffset.png")
}

View File

@@ -18,6 +18,7 @@
*/
package org.isoron.uhabits.activities.common.views
import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest
@@ -44,7 +45,7 @@ class ScoreChartTest : BaseViewTest() {
habit = habit,
firstWeekday = prefs.firstWeekdayInt,
spinnerPosition = 0,
theme = LightTheme(),
theme = LightTheme()
)
view = ScoreChart(targetContext).apply {
setScores(state.scores)
@@ -63,7 +64,8 @@ class ScoreChartTest : BaseViewTest() {
@Test
@Throws(Throwable::class)
fun testRender_withDataOffset() {
view.onScroll(null, null, -dpToPixels(150), 0f)
val e = MotionEvent.obtain(0, 0, 0, 0f, 0f, 0)
view.onScroll(e, e, -dpToPixels(150), 0f)
view.invalidate()
assertRenders(view, BASE_PATH + "renderDataOffset.png")
}

View File

@@ -30,6 +30,7 @@ import org.junit.runner.RunWith
@MediumTest
class StreakChartTest : BaseViewTest() {
private lateinit var view: StreakChart
@Before
override fun setUp() {
super.setUp()

View File

@@ -22,7 +22,7 @@ package org.isoron.uhabits.activities.habits.list.views
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import org.isoron.uhabits.BaseViewTest
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
@@ -35,23 +35,22 @@ class EmptyListViewTest : BaseViewTest() {
}
private val path = "habits/list/EmptyListView"
private val view: EmptyListView = EmptyListView(targetContext)
@Before
override fun setUp() {
super.setUp()
measureView(view, dpToPixels(200), dpToPixels(200))
}
@Test
@Ignore("non-deterministic failure")
fun testRender_done() {
val view = EmptyListView(targetContext)
view.showDone()
measureView(view, dpToPixels(200), dpToPixels(200))
assertRenders(view, "$path/done.png")
}
@Test
@Ignore("non-deterministic failure")
fun testRender_empty() {
val view = EmptyListView(targetContext)
view.showEmpty()
measureView(view, dpToPixels(200), dpToPixels(200))
assertRenders(view, "$path/empty.png")
}
}

View File

@@ -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))

View File

@@ -77,7 +77,7 @@ class EntryPanelViewTest : BaseViewTest() {
@Test
fun testToggle() {
val timestamps = mutableListOf<Timestamp>()
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<Timestamp>()
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()

View File

@@ -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

View File

@@ -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

View File

@@ -48,7 +48,7 @@ class FrequencyCardViewTest : BaseViewTest() {
FrequencyCardPresenter.buildState(
habit = habit,
firstWeekday = 0,
theme = LightTheme(),
theme = LightTheme()
)
)
measureView(view, 800f, 600f)

View File

@@ -49,7 +49,7 @@ class HistoryCardViewTest : BaseViewTest() {
HistoryCardPresenter.buildState(
habit = habit,
firstWeekday = SUNDAY,
theme = LightTheme(),
theme = LightTheme()
)
)
measureView(view, 800f, 600f)

View File

@@ -51,7 +51,7 @@ class OverviewCardViewTest : BaseViewTest() {
scoreYearDiff = 0.74f,
totalCount = 44,
color = PaletteColor(7),
theme = LightTheme(),
theme = LightTheme()
)
)
measureView(view, 800f, 300f)

View File

@@ -49,7 +49,7 @@ class ScoreCardViewTest : BaseViewTest() {
habit = habit,
firstWeekday = 0,
spinnerPosition = 0,
theme = LightTheme(),
theme = LightTheme()
)
)
measureView(view, 800f, 600f)

View File

@@ -48,7 +48,7 @@ class StreakCardViewTest : BaseViewTest() {
StreakCardState(
bestStreaks = habit.streaks.getBest(10),
color = habit.color,
theme = LightTheme(),
theme = LightTheme()
)
)
measureView(view, 800f, 600f)

View File

@@ -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)

View File

@@ -119,7 +119,7 @@ class ListHabitsRegressionTest : BaseUserInterfaceTest() {
"Wake up early",
"Meditate",
"Read books",
"Track time",
"Track time"
)
}
}

View File

@@ -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

View File

@@ -16,13 +16,13 @@
~ You should have received a copy of the GNU General Public License along
~ with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.isoron.uhabits">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:name=".HabitsApplication"
@@ -30,6 +30,7 @@
android:backupAgent=".HabitsBackupAgent"
android:icon="@mipmap/ic_launcher"
android:label="@string/main_activity_title"
android:localeConfig="@xml/locales_config"
android:supportsRtl="true"
android:theme="@style/AppBaseTheme">

View File

@@ -22,7 +22,6 @@ import java.util.Locale;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;

View File

@@ -23,14 +23,13 @@ import android.graphics.Paint.*;
import android.os.*;
import androidx.core.view.*;
import androidx.core.view.accessibility.*;
import androidx.core.widget.*;
import android.text.format.*;
import android.view.*;
import android.view.accessibility.*;
import androidx.customview.widget.ExploreByTouchHelper;
import com.android.*;
import com.android.datetimepicker.*;
import com.android.datetimepicker.date.MonthAdapter.*;

View File

@@ -23,7 +23,6 @@ import android.graphics.Paint.*;
import android.util.*;
import android.view.*;
import com.android.*;
import com.android.datetimepicker.*;
import org.isoron.uhabits.R;

View File

@@ -28,7 +28,6 @@ import android.view.View.*;
import android.view.accessibility.*;
import android.widget.*;
import com.android.*;
import com.android.datetimepicker.*;
import org.isoron.uhabits.R;

View File

@@ -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)

View File

@@ -33,7 +33,7 @@ import kotlin.math.max
*/
class AndroidDataView(
context: Context,
attrs: AttributeSet? = null,
attrs: AttributeSet? = null
) : AndroidView<DataView>(context, attrs),
GestureDetector.OnGestureListener,
ValueAnimator.AnimatorUpdateListener {
@@ -44,23 +44,23 @@ class AndroidDataView(
addUpdateListener(this@AndroidDataView)
}
override fun onTouchEvent(event: MotionEvent?) = detector.onTouchEvent(event)
override fun onDown(e: MotionEvent?) = true
override fun onShowPress(e: MotionEvent?) = Unit
override fun onTouchEvent(event: MotionEvent) = detector.onTouchEvent(event)
override fun onDown(e: MotionEvent) = true
override fun onShowPress(e: MotionEvent) = Unit
override fun onSingleTapUp(e: MotionEvent?): Boolean {
override fun onSingleTapUp(e: MotionEvent): Boolean {
return handleClick(e, true)
}
override fun onLongPress(e: MotionEvent?) {
override fun onLongPress(e: MotionEvent) {
handleClick(e)
}
override fun onScroll(
e1: MotionEvent?,
e2: MotionEvent?,
e2: MotionEvent,
dx: Float,
dy: Float,
dy: Float
): Boolean {
if (abs(dx) > abs(dy)) {
val parent = parent
@@ -80,9 +80,9 @@ class AndroidDataView(
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float,
velocityY: Float
): Boolean {
scroller.fling(
scroller.currX,
@@ -100,7 +100,7 @@ class AndroidDataView(
return false
}
override fun onAnimationUpdate(animation: ValueAnimator?) {
override fun onAnimationUpdate(animation: ValueAnimator) {
if (!scroller.isFinished) {
scroller.computeScrollOffset()
updateDataOffset()
@@ -127,11 +127,11 @@ class AndroidDataView(
}
}
private fun handleClick(e: MotionEvent?, isSingleTap: Boolean = false): Boolean {
private fun handleClick(e: MotionEvent, isSingleTap: Boolean = false): Boolean {
val x: Float
val y: Float
try {
val pointerId = e!!.getPointerId(0)
val pointerId = e.getPointerId(0)
x = e.getX(pointerId)
y = e.getY(pointerId)
} catch (ex: RuntimeException) {
@@ -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
}
}

View File

@@ -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()
)
}

View File

@@ -24,7 +24,7 @@ import android.util.AttributeSet
open class AndroidView<T : View>(
context: Context,
attrs: AttributeSet? = null,
attrs: AttributeSet? = null
) : android.view.View(context, attrs) {
var view: T? = null

View File

@@ -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()

View File

@@ -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

View File

@@ -26,13 +26,14 @@ import org.isoron.uhabits.BuildConfig
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.databinding.AboutBinding
import org.isoron.uhabits.utils.applyRootViewInsets
import org.isoron.uhabits.utils.currentTheme
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 +44,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() }
@@ -54,5 +55,6 @@ class AboutView(
binding.tvTranslate.setOnClickListener { screen.showTranslationWebsite() }
binding.tvVersion.setOnClickListener { screen.onPressDeveloperCountdown() }
binding.tvVersion.text = String.format(version, BuildConfig.VERSION_NAME)
applyRootViewInsets()
}
}

View File

@@ -20,109 +20,61 @@
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))
val color = requireArguments().getInt("color")
arrayOf(view.yesBtn, view.skipBtn).forEach {
it.setTextColor(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
}
}

View File

@@ -19,6 +19,7 @@
package org.isoron.uhabits.activities.common.dialogs
import android.content.Context
import com.android.colorpicker.ColorPickerDialog.SIZE_SMALL
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.PaletteColor
@@ -39,7 +40,7 @@ class ColorPickerDialogFactory @Inject constructor(@param:ActivityContext privat
res.getPalette(),
androidColor,
4,
com.android.colorpicker.ColorPickerDialog.SIZE_SMALL
SIZE_SMALL
)
return dialog
}

View File

@@ -22,97 +22,101 @@ package org.isoron.uhabits.activities.common.dialogs
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import android.widget.LinearLayout
import android.widget.RadioButton
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment
import kotlinx.android.synthetic.main.frequency_picker_dialog.view.*
import org.isoron.uhabits.R
import org.isoron.uhabits.databinding.FrequencyPickerDialogBinding
class FrequencyPickerDialog(
var freqNumerator: Int,
var freqDenominator: Int
) : AppCompatDialogFragment() {
private var _binding: FrequencyPickerDialogBinding? = null
private val binding get() = _binding!!
lateinit var contentView: View
var onFrequencyPicked: (num: Int, den: Int) -> Unit = { _, _ -> }
constructor() : this(1, 1)
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val inflater = LayoutInflater.from(requireActivity())
contentView = inflater.inflate(R.layout.frequency_picker_dialog, null)
_binding = FrequencyPickerDialogBinding.inflate(LayoutInflater.from(requireActivity()))
addBeforeAfterText(
this.getString(R.string.every_x_days),
contentView.everyXDaysContainer,
binding.everyXDaysContainer
)
addBeforeAfterText(
this.getString(R.string.x_times_per_week),
contentView.xTimesPerWeekContainer,
binding.xTimesPerWeekContainer
)
addBeforeAfterText(
this.getString(R.string.x_times_per_month),
contentView.xTimesPerMonthContainer,
binding.xTimesPerMonthContainer
)
addBeforeAfterText(
this.getString(R.string.x_times_per_y_days),
contentView.xTimesPerYDaysContainer,
binding.xTimesPerYDaysContainer
)
contentView.everyDayRadioButton.setOnClickListener {
check(contentView.everyDayRadioButton)
binding.everyDayRadioButton.setOnClickListener {
check(binding.everyDayRadioButton)
}
contentView.everyXDaysRadioButton.setOnClickListener {
check(contentView.everyXDaysRadioButton)
val everyXDaysTextView = contentView.everyXDaysTextView
binding.everyXDaysRadioButton.setOnClickListener {
check(binding.everyXDaysRadioButton)
val everyXDaysTextView = binding.everyXDaysTextView
selectInputField(everyXDaysTextView)
}
contentView.everyXDaysTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(contentView.everyXDaysRadioButton)
binding.everyXDaysTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(binding.everyXDaysRadioButton)
}
contentView.xTimesPerWeekRadioButton.setOnClickListener {
check(contentView.xTimesPerWeekRadioButton)
selectInputField(contentView.xTimesPerWeekTextView)
binding.xTimesPerWeekRadioButton.setOnClickListener {
check(binding.xTimesPerWeekRadioButton)
selectInputField(binding.xTimesPerWeekTextView)
}
contentView.xTimesPerWeekTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(contentView.xTimesPerWeekRadioButton)
binding.xTimesPerWeekTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(binding.xTimesPerWeekRadioButton)
}
contentView.xTimesPerMonthRadioButton.setOnClickListener {
check(contentView.xTimesPerMonthRadioButton)
selectInputField(contentView.xTimesPerMonthTextView)
binding.xTimesPerMonthRadioButton.setOnClickListener {
check(binding.xTimesPerMonthRadioButton)
selectInputField(binding.xTimesPerMonthTextView)
}
contentView.xTimesPerMonthTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(contentView.xTimesPerMonthRadioButton)
binding.xTimesPerMonthTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(binding.xTimesPerMonthRadioButton)
}
contentView.xTimesPerYDaysRadioButton.setOnClickListener {
check(contentView.xTimesPerYDaysRadioButton)
selectInputField(contentView.xTimesPerYDaysXTextView)
binding.xTimesPerYDaysRadioButton.setOnClickListener {
check(binding.xTimesPerYDaysRadioButton)
selectInputField(binding.xTimesPerYDaysXTextView)
}
contentView.xTimesPerYDaysXTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(contentView.xTimesPerYDaysRadioButton)
binding.xTimesPerYDaysXTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(binding.xTimesPerYDaysRadioButton)
}
contentView.xTimesPerYDaysYTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(contentView.xTimesPerYDaysRadioButton)
binding.xTimesPerYDaysYTextView.setOnFocusChangeListener { v, hasFocus ->
if (hasFocus) check(binding.xTimesPerYDaysRadioButton)
}
return AlertDialog.Builder(requireActivity())
.setView(contentView)
.setView(binding.root)
.setPositiveButton(R.string.save) { _, _ -> onSaveClicked() }
.create()
}
@@ -124,7 +128,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
)
}
}
@@ -133,31 +138,35 @@ class FrequencyPickerDialog(
var numerator = 1
var denominator = 1
when {
contentView.everyDayRadioButton.isChecked -> {
binding.everyDayRadioButton.isChecked -> {
// NOP
}
contentView.everyXDaysRadioButton.isChecked -> {
if (contentView.everyXDaysTextView.text.isNotEmpty()) {
denominator = Integer.parseInt(contentView.everyXDaysTextView.text.toString())
binding.everyXDaysRadioButton.isChecked -> {
if (binding.everyXDaysTextView.text.isNotEmpty()) {
denominator = Integer.parseInt(binding.everyXDaysTextView.text.toString())
}
}
contentView.xTimesPerWeekRadioButton.isChecked -> {
if (contentView.xTimesPerWeekTextView.text.isNotEmpty()) {
numerator = Integer.parseInt(contentView.xTimesPerWeekTextView.text.toString())
binding.xTimesPerWeekRadioButton.isChecked -> {
if (binding.xTimesPerWeekTextView.text.isNotEmpty()) {
numerator = Integer.parseInt(binding.xTimesPerWeekTextView.text.toString())
denominator = 7
}
}
contentView.xTimesPerYDaysRadioButton.isChecked -> {
if (contentView.xTimesPerYDaysXTextView.text.isNotEmpty() && contentView.xTimesPerYDaysYTextView.text.isNotEmpty()) {
binding.xTimesPerYDaysRadioButton.isChecked -> {
if (binding.xTimesPerYDaysXTextView.text.isNotEmpty() && binding.xTimesPerYDaysYTextView.text.isNotEmpty()) {
numerator =
Integer.parseInt(contentView.xTimesPerYDaysXTextView.text.toString())
Integer.parseInt(binding.xTimesPerYDaysXTextView.text.toString())
denominator =
Integer.parseInt(contentView.xTimesPerYDaysYTextView.text.toString())
Integer.parseInt(binding.xTimesPerYDaysYTextView.text.toString())
}
}
else -> {
if (contentView.xTimesPerMonthTextView.text.isNotEmpty()) {
numerator = Integer.parseInt(contentView.xTimesPerMonthTextView.text.toString())
if (binding.xTimesPerMonthTextView.text.isNotEmpty()) {
numerator = Integer.parseInt(binding.xTimesPerMonthTextView.text.toString())
denominator = 30
}
}
@@ -184,27 +193,27 @@ class FrequencyPickerDialog(
private fun populateViews() {
uncheckAll()
if (freqDenominator == 30 || freqDenominator == 31) {
contentView.xTimesPerMonthRadioButton.isChecked = true
contentView.xTimesPerMonthTextView.setText(freqNumerator.toString())
selectInputField(contentView.xTimesPerMonthTextView)
binding.xTimesPerMonthRadioButton.isChecked = true
binding.xTimesPerMonthTextView.setText(freqNumerator.toString())
selectInputField(binding.xTimesPerMonthTextView)
} else {
if (freqNumerator == 1) {
if (freqDenominator == 1) {
contentView.everyDayRadioButton.isChecked = true
binding.everyDayRadioButton.isChecked = true
} else {
contentView.everyXDaysRadioButton.isChecked = true
contentView.everyXDaysTextView.setText(freqDenominator.toString())
selectInputField(contentView.everyXDaysTextView)
binding.everyXDaysRadioButton.isChecked = true
binding.everyXDaysTextView.setText(freqDenominator.toString())
selectInputField(binding.everyXDaysTextView)
}
} else {
if (freqDenominator == 7) {
contentView.xTimesPerWeekRadioButton.isChecked = true
contentView.xTimesPerWeekTextView.setText(freqNumerator.toString())
selectInputField(contentView.xTimesPerWeekTextView)
binding.xTimesPerWeekRadioButton.isChecked = true
binding.xTimesPerWeekTextView.setText(freqNumerator.toString())
selectInputField(binding.xTimesPerWeekTextView)
} else {
contentView.xTimesPerYDaysRadioButton.isChecked = true
contentView.xTimesPerYDaysXTextView.setText(freqNumerator.toString())
contentView.xTimesPerYDaysYTextView.setText(freqDenominator.toString())
binding.xTimesPerYDaysRadioButton.isChecked = true
binding.xTimesPerYDaysXTextView.setText(freqNumerator.toString())
binding.xTimesPerYDaysYTextView.setText(freqDenominator.toString())
}
}
}
@@ -215,10 +224,10 @@ class FrequencyPickerDialog(
}
private fun uncheckAll() {
contentView.everyDayRadioButton.isChecked = false
contentView.everyXDaysRadioButton.isChecked = false
contentView.xTimesPerWeekRadioButton.isChecked = false
contentView.xTimesPerMonthRadioButton.isChecked = false
contentView.xTimesPerYDaysRadioButton.isChecked = false
binding.everyDayRadioButton.isChecked = false
binding.everyXDaysRadioButton.isChecked = false
binding.xTimesPerWeekRadioButton.isChecked = false
binding.xTimesPerMonthRadioButton.isChecked = false
binding.xTimesPerYDaysRadioButton.isChecked = false
}
}

View File

@@ -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!!

View File

@@ -0,0 +1,128 @@
package org.isoron.uhabits.activities.common.dialogs
import android.app.Dialog
import android.os.Bundle
import android.provider.Settings
import android.text.method.DigitsKeyListener
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.appcompat.app.AppCompatDialogFragment
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
import org.isoron.uhabits.core.models.Entry
import org.isoron.uhabits.databinding.CheckmarkPopupBinding
import org.isoron.uhabits.utils.InterfaceUtils
import org.isoron.uhabits.utils.getCenter
import org.isoron.uhabits.utils.requestFocusWithKeyboard
import org.isoron.uhabits.utils.sres
import java.text.DecimalFormat
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).forEach {
it.setTextColor(requireArguments().getInt("color"))
}
arrayOf(view.noBtn, view.unknownBtnNumber).forEach {
it.setTextColor(view.root.sres.getColor(R.attr.contrast60))
}
arrayOf(view.yesBtn, view.noBtn, view.unknownBtnNumber).forEach {
it.typeface = InterfaceUtils.getFontAwesome(requireContext())
}
if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = View.GONE
if (!prefs.areQuestionMarksEnabled) view.unknownBtnNumber.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(DecimalFormat("#.###").format((Entry.SKIP.toDouble() / 1000)))
save()
}
view.unknownBtnNumber.setOnClickListener {
view.value.setText(DecimalFormat("#.###").format((Entry.UNKNOWN.toDouble() / 1000)))
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")
// https://github.com/flutter/flutter/issues/61175
val currKeyboard = Settings.Secure.getString(
requireContext().contentResolver,
Settings.Secure.DEFAULT_INPUT_METHOD
)
if (currKeyboard.contains("swiftkey") || currKeyboard.contains("samsung")) {
view.value.inputType = EditorInfo.TYPE_CLASS_TEXT
}
}
fun save() {
var value = originalValue
try {
val numberFormat = NumberFormat.getInstance()
val valueStr = view.value.text.toString()
value = if (valueStr.isNotEmpty()) {
numberFormat.parse(valueStr)!!.toDouble()
} else {
Entry.UNKNOWN.toDouble() / 1000
}
} catch (e: ParseException) {
// NOP
}
val notes = view.notes.text.toString()
val location = view.saveBtn.getCenter()
onToggle(value, notes)
requireDialog().dismiss()
}
}

View File

@@ -1,116 +0,0 @@
/*
* Copyright (C) 2016-2021 Álinson Santos Xavier <git@axavier.org>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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()
}
}

View File

@@ -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?) {

View File

@@ -58,6 +58,7 @@ class RingView : View {
private var em = 0f
private var text: String?
private var textSize: Float
private var isStrokedTextEnabled: Boolean = false
private var enableFontAwesome = false
private var internalDrawingCache: Bitmap? = null
private var cacheCanvas: Canvas? = null
@@ -131,6 +132,10 @@ class RingView : View {
invalidate()
}
fun setIsStrokedTextEnabled(isStroked: Boolean) {
this.isStrokedTextEnabled = isStroked
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val activeCanvas: Canvas?
@@ -148,13 +153,23 @@ 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
pRing!!.color = color
pRing!!.textSize = textSize
if (isStrokedTextEnabled) {
pRing!!.style = Paint.Style.STROKE
pRing!!.strokeWidth = textSize / 15f
}
if (enableFontAwesome) pRing!!.typeface = getFontAwesome(context)
activeCanvas.drawText(
text!!,

View File

@@ -65,7 +65,7 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
}
override fun onFling(
e1: MotionEvent,
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
@@ -116,7 +116,7 @@ abstract class ScrollableChart : View, GestureDetector.OnGestureListener, Animat
return BundleSavedState(superState, bundle)
}
override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, dx: Float, dy: Float): Boolean {
override fun onScroll(e1: MotionEvent?, e2: MotionEvent, dx: Float, dy: Float): Boolean {
var dx = dx
if (scrollerBucketSize == 0) return false
if (abs(dx) > abs(dy)) {

View File

@@ -22,7 +22,6 @@ package org.isoron.uhabits.activities.habits.edit
import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Color
import android.os.Bundle
import android.text.Html
import android.text.Spanned
@@ -35,11 +34,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import com.android.datetimepicker.time.RadialPickerLayout
import com.android.datetimepicker.time.TimePickerDialog
import kotlinx.android.synthetic.main.activity_edit_habit.nameInput
import kotlinx.android.synthetic.main.activity_edit_habit.notesInput
import kotlinx.android.synthetic.main.activity_edit_habit.questionInput
import kotlinx.android.synthetic.main.activity_edit_habit.targetInput
import kotlinx.android.synthetic.main.activity_edit_habit.unitInput
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
@@ -58,7 +52,8 @@ import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.core.models.Reminder
import org.isoron.uhabits.core.models.WeekdayList
import org.isoron.uhabits.databinding.ActivityEditHabitBinding
import org.isoron.uhabits.utils.ColorUtils
import org.isoron.uhabits.utils.applyRootViewInsets
import org.isoron.uhabits.utils.applyToolbarInsets
import org.isoron.uhabits.utils.dismissCurrentAndShow
import org.isoron.uhabits.utils.formatTime
import org.isoron.uhabits.utils.toFormattedString
@@ -99,6 +94,8 @@ class EditHabitActivity : AppCompatActivity() {
themeSwitcher.apply()
binding = ActivityEditHabitBinding.inflate(layoutInflater)
binding.root.applyRootViewInsets()
binding.toolbar.applyToolbarInsets()
setContentView(binding.root)
if (intent.hasExtra("habitId")) {
@@ -271,9 +268,9 @@ class EditHabitActivity : AppCompatActivity() {
habit.copyFrom(original)
}
habit.name = nameInput.text.trim().toString()
habit.question = questionInput.text.trim().toString()
habit.description = notesInput.text.trim().toString()
habit.name = binding.nameInput.text.trim().toString()
habit.question = binding.questionInput.text.trim().toString()
habit.description = binding.notesInput.text.trim().toString()
habit.color = color
if (reminderHour >= 0) {
habit.reminder = Reminder(reminderHour, reminderMin, reminderDays)
@@ -283,9 +280,9 @@ class EditHabitActivity : AppCompatActivity() {
habit.frequency = Frequency(freqNum, freqDen)
if (habitType == HabitType.NUMERICAL) {
habit.targetValue = targetInput.text.toString().toDouble()
habit.targetValue = binding.targetInput.text.toString().toDouble()
habit.targetType = targetType
habit.unit = unitInput.text.trim().toString()
habit.unit = binding.unitInput.text.trim().toString()
}
habit.type = habitType
@@ -308,13 +305,13 @@ class EditHabitActivity : AppCompatActivity() {
private fun validate(): Boolean {
var isValid = true
if (nameInput.text.isEmpty()) {
nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
if (binding.nameInput.text.isEmpty()) {
binding.nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
isValid = false
}
if (habitType == HabitType.NUMERICAL) {
if (targetInput.text.isEmpty()) {
targetInput.error = getString(R.string.validation_cannot_be_blank)
if (binding.targetInput.text.isEmpty()) {
binding.targetInput.error = getString(R.string.validation_cannot_be_blank)
isValid = false
}
}
@@ -357,8 +354,7 @@ class EditHabitActivity : AppCompatActivity() {
androidColor = themeSwitcher.currentTheme.color(color).toInt()
binding.colorButton.backgroundTintList = ColorStateList.valueOf(androidColor)
if (!themeSwitcher.isNightMode) {
val darkerAndroidColor = ColorUtils.mixColors(Color.BLACK, androidColor, 0.15f)
window.statusBarColor = darkerAndroidColor
window.statusBarColor = androidColor
binding.toolbar.setBackgroundColor(androidColor)
}
}

View File

@@ -19,12 +19,17 @@
package org.isoron.uhabits.activities.habits.list
import android.Manifest.permission.POST_NOTIFICATIONS
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat.checkSelfPermission
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.isoron.uhabits.BaseExceptionHandler
@@ -40,6 +45,8 @@ 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.applyRootViewInsets
import org.isoron.uhabits.utils.dismissCurrentDialog
import org.isoron.uhabits.utils.restartWithFade
class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
@@ -55,6 +62,16 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
lateinit var midnightTimer: MidnightTimer
private val scope = CoroutineScope(Dispatchers.Main)
private var permissionAlreadyRequested = false
private val permissionLauncher =
registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
scheduleReminders()
} else {
Log.i("ListHabitsActivity", "POST_NOTIFICATIONS denied")
}
}
private lateinit var menu: ListHabitsMenu
override fun onQuestionMarksChanged() {
@@ -84,6 +101,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
menu = component.listHabitsMenu
Thread.setDefaultUncaughtExceptionHandler(BaseExceptionHandler(this))
component.listHabitsBehavior.onStartup()
rootView.applyRootViewInsets()
setContentView(rootView)
}
@@ -91,6 +109,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
midnightTimer.onPause()
screen.onDetached()
adapter.cancelRefresh()
dismissCurrentDialog()
super.onPause()
}
@@ -99,6 +118,26 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
screen.onAttached()
rootView.postInvalidate()
midnightTimer.onResume()
if (appComponent.reminderScheduler.hasHabitsWithReminders()) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
scheduleReminders()
} else {
if (checkSelfPermission(this, POST_NOTIFICATIONS) == PERMISSION_GRANTED) {
scheduleReminders()
} else {
// If we have not requested the permission yet, request it. Otherwide do
// nothing. This check is necessary to avoid an infinite onResume loop in case
// the user denies the permission.
if (!permissionAlreadyRequested) {
Log.i("ListHabitsActivity", "Requestion permission: POST_NOTIFICATIONS")
permissionLauncher.launch(POST_NOTIFICATIONS)
permissionAlreadyRequested = true
}
}
}
}
taskRunner.run {
try {
AutoBackup(this@ListHabitsActivity).run()
@@ -114,6 +153,10 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
super.onResume()
}
private fun scheduleReminders() {
appComponent.reminderScheduler.scheduleAll()
}
override fun onCreateOptionsMenu(m: Menu): Boolean {
menu.onCreate(menuInflater, m)
return true
@@ -124,6 +167,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
return menu.onItemSelected(item)
}
@Deprecated("Deprecated in Java")
override fun onActivityResult(request: Int, result: Int, data: Intent?) {
super.onActivityResult(request, result, data)
screen.onResult(request, result, data)
@@ -136,7 +180,7 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
val timestamp = intent.extras?.getLong("timestamp")
if (habitId != null && timestamp != null) {
val habit = appComponent.habitList.getById(habitId)!!
component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp))
component.listHabitsBehavior.onEdit(habit, Timestamp(timestamp), 0f, 0f)
}
}
intent = null

View File

@@ -23,6 +23,7 @@ import android.content.Context
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import android.widget.RelativeLayout
import nl.dionsegijn.konfetti.xml.KonfettiView
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.common.views.ScrollableChart
import org.isoron.uhabits.activities.common.views.TaskProgressBar
@@ -69,6 +70,9 @@ class ListHabitsRootView @Inject constructor(
val listView: HabitCardListView = habitCardListViewFactory.create()
val llEmpty = EmptyListView(context)
val tbar = buildToolbar()
val konfettiView = KonfettiView(context).apply {
translationZ = 10f
}
val progressBar = TaskProgressBar(context, runner)
val hintView: HintView
val header = HeaderView(context, preferences, midnightTimer)
@@ -80,6 +84,7 @@ class ListHabitsRootView @Inject constructor(
val rootView = RelativeLayout(context).apply {
background = sres.getDrawable(R.attr.windowBackgroundColor)
addAtTop(konfettiView)
addAtTop(tbar)
addBelow(header, tbar)
addBelow(listView, header, height = MATCH_PARENT)
@@ -94,7 +99,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)

View File

@@ -22,14 +22,18 @@ 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 nl.dionsegijn.konfetti.core.Party
import nl.dionsegijn.konfetti.core.Position
import nl.dionsegijn.konfetti.core.emitter.Emitter
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.common.dialogs.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
@@ -62,6 +66,7 @@ import org.isoron.uhabits.intents.IntentFactory
import org.isoron.uhabits.tasks.ExportDBTaskFactory
import org.isoron.uhabits.tasks.ImportDataTask
import org.isoron.uhabits.tasks.ImportDataTaskFactory
import org.isoron.uhabits.utils.ColorUtils
import org.isoron.uhabits.utils.copyTo
import org.isoron.uhabits.utils.currentTheme
import org.isoron.uhabits.utils.dismissCurrentAndShow
@@ -71,6 +76,7 @@ import org.isoron.uhabits.utils.showSendEmailScreen
import org.isoron.uhabits.utils.showSendFileScreen
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
const val RESULT_IMPORT_DATA = 101
@@ -95,7 +101,7 @@ class ListHabitsScreen
private val colorPickerFactory: ColorPickerDialogFactory,
private val behavior: Lazy<ListHabitsBehavior>,
private val preferences: Preferences,
private val rootView: Lazy<ListHabitsRootView>,
private val rootView: Lazy<ListHabitsRootView>
) : CommandRunner.Listener,
ListHabitsBehavior.Screen,
ListHabitsMenuBehavior.Screen,
@@ -217,6 +223,30 @@ class ListHabitsScreen
activity.showSendFileScreen(filename)
}
override fun showConfetti(color: PaletteColor, x: Float, y: Float) {
if (x == 0f && y == 0f) return
if (preferences.isConfettiAnimationDisabled) return
val baseColor = themeSwitcher.currentTheme!!.color(color).toInt()
rootView.get().konfettiView.start(
Party(
speed = 0f,
maxSpeed = 16f,
damping = 0.9f,
spread = 360,
angle = 0,
colors = listOf(
ColorUtils.changeHue(baseColor, 180f),
ColorUtils.changeHue(baseColor, 20f),
ColorUtils.changeHue(baseColor, -20f),
baseColor
),
position = Position.Absolute(x, y),
emitter = Emitter(duration = 25, TimeUnit.MILLISECONDS).max(25),
timeToLive = 0
)
)
}
override fun showSettingsScreen() {
val intent = intentFactory.startSettingsActivity(activity)
activity.startActivityForResult(intent, REQUEST_SETTINGS)
@@ -233,17 +263,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 +279,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 +350,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))
}
}
)
}

View File

@@ -60,8 +60,11 @@ abstract class ButtonPanelView<T : View>(
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()
}

View File

@@ -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
}

View File

@@ -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) }
}
}

View File

@@ -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()
}
}
}
}

View File

@@ -20,6 +20,7 @@
package org.isoron.uhabits.activities.habits.list.views
import android.content.Context
import android.graphics.PointF
import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED
import android.os.Build
import android.os.Build.VERSION.SDK_INT
@@ -57,13 +58,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 +130,6 @@ class HabitCardView(
private var scoreRing: RingView
private var currentToggleTaskId = 0
private var queuedToggles = mutableListOf<DelayedToggle>()
init {
scoreRing = RingView(context).apply {
@@ -160,16 +153,24 @@ class HabitCardView(
}
checkmarkPanel = checkmarkPanelFactory.create().apply {
onToggle = { timestamp, value, notes, delay ->
if (delay > 0) triggerRipple(timestamp)
onToggle = { timestamp, value, notes ->
triggerRipple(timestamp)
val location = getAbsoluteButtonLocation(timestamp)
habit?.let {
val taskId = queueToggle(it, timestamp, value, notes);
{ runPendingToggles(taskId) }.delay(delay)
behavior.onToggle(
it,
timestamp,
value,
notes,
location.x,
location.y
)
}
}
onEdit = { timestamp ->
triggerRipple(timestamp)
habit?.let { behavior.onEdit(it, timestamp) }
val location = getAbsoluteButtonLocation(timestamp)
habit?.let { behavior.onEdit(it, timestamp, location.x, location.y) }
}
}
@@ -177,7 +178,8 @@ class HabitCardView(
visibility = GONE
onEdit = { timestamp ->
triggerRipple(timestamp)
habit?.let { behavior.onEdit(it, timestamp) }
val location = getAbsoluteButtonLocation(timestamp)
habit?.let { behavior.onEdit(it, timestamp, location.x, location.y) }
}
}
@@ -205,25 +207,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) }
@@ -236,12 +219,37 @@ class HabitCardView(
}
fun triggerRipple(timestamp: Timestamp) {
val location = getRelativeButtonLocation(timestamp)
triggerRipple(location.x, location.y)
}
private fun getRelativeButtonLocation(timestamp: Timestamp): PointF {
val today = DateUtils.getTodayWithOffset()
val offset = timestamp.daysUntil(today) - dataOffset
val button = checkmarkPanel.buttons[offset]
val panel = when (habit!!.isNumerical) {
true -> numberPanel
false -> checkmarkPanel
}
val button = panel.buttons[offset]
val y = button.height / 2.0f
val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat()
triggerRipple(x, y)
val x = panel.x + button.x + (button.width / 2).toFloat()
return PointF(x, y)
}
private fun getAbsoluteButtonLocation(timestamp: Timestamp): PointF {
val containerLocation = IntArray(2)
this.getLocationOnScreen(containerLocation)
val relButtonLocation = getRelativeButtonLocation(timestamp)
val windowInsets = rootWindowInsets
val statusBarHeight = if (SDK_INT <= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
windowInsets?.systemWindowInsetTop ?: 0
} else {
0
}
return PointF(
containerLocation[0].toFloat() + relButtonLocation.x,
containerLocation[1].toFloat() + relButtonLocation.y - statusBarHeight
)
}
override fun onAttachedToWindow() {
@@ -255,7 +263,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 +308,6 @@ class HabitCardView(
}
private fun updateBackground(isSelected: Boolean) {
val background = when (isSelected) {
true -> R.drawable.selected_box
false -> R.drawable.ripple

View File

@@ -124,19 +124,24 @@ 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 (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 (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
val lines = DateUtils.formatHeaderDate(day).toUpperCase().split("\n")
val lines = DateUtils.formatHeaderDate(day).uppercase().split("\n")
canvas.drawText(lines[0], rect.centerX(), y1.toFloat(), paint)
canvas.drawText(lines[1], rect.centerX(), y2.toFloat(), paint)
day.add(GregorianCalendar.DAY_OF_MONTH, -1)

View File

@@ -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
@@ -49,8 +49,10 @@ import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitMenuPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter
import org.isoron.uhabits.core.ui.views.OnDateClickedListener
import org.isoron.uhabits.intents.IntentFactory
import org.isoron.uhabits.utils.applyRootViewInsets
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 +89,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
habit = habit,
habitList = habitList,
preferences = preferences,
screen = screen,
screen = screen
)
view = ShowHabitView(this)
@@ -98,16 +100,17 @@ 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)
view.applyRootViewInsets()
setContentView(view)
}
@@ -129,6 +132,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
}
override fun onPause() {
dismissCurrentDialog()
commandRunner.removeListener(this)
super.onPause()
}
@@ -148,7 +152,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
ShowHabitPresenter.buildState(
habit = habit,
preferences = preferences,
theme = themeSwitcher.currentTheme,
theme = themeSwitcher.currentTheme
)
)
}
@@ -170,41 +174,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? {

View File

@@ -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)

View File

@@ -25,12 +25,14 @@ import android.widget.FrameLayout
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitPresenter
import org.isoron.uhabits.core.ui.screens.habits.show.ShowHabitState
import org.isoron.uhabits.databinding.ShowHabitBinding
import org.isoron.uhabits.utils.applyToolbarInsets
import org.isoron.uhabits.utils.setupToolbar
class ShowHabitView(context: Context) : FrameLayout(context) {
private val binding = ShowHabitBinding.inflate(LayoutInflater.from(context))
init {
binding.toolbar.applyToolbarInsets()
addView(binding.root)
}
@@ -39,7 +41,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)
@@ -52,7 +54,6 @@ class ShowHabitView(context: Context) : FrameLayout(context) {
binding.barCard.setState(data.bar)
if (data.isNumerical) {
binding.overviewCard.visibility = GONE
binding.streakCard.visibility = GONE
} else {
binding.targetCard.visibility = GONE
}

View File

@@ -38,7 +38,7 @@ class BarCardView(context: Context, attrs: AttributeSet) : LinearLayout(context,
fun setState(state: BarCardState) {
val androidColor = state.theme.color(state.color).toInt()
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.US)).apply {
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.getDefault())).apply {
series = mutableListOf(state.entries.map { it.value / 1000.0 })
colors = mutableListOf(theme.color(state.color.paletteIndex))
axis = state.entries.map { it.timestamp.toLocalDate() }
@@ -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)
}

View File

@@ -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()
}

View File

@@ -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

View File

@@ -26,6 +26,7 @@ import org.isoron.uhabits.R
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.databinding.SettingsActivityBinding
import org.isoron.uhabits.utils.applyRootViewInsets
import org.isoron.uhabits.utils.setupToolbar
class SettingsActivity : AppCompatActivity() {
@@ -40,8 +41,9 @@ class SettingsActivity : AppCompatActivity() {
toolbar = binding.toolbar,
title = resources.getString(R.string.settings),
color = PaletteColor(11),
theme = themeSwitcher.currentTheme,
theme = themeSwitcher.currentTheme
)
binding.root.applyRootViewInsets()
setContentView(binding.root)
}
}

View File

@@ -53,6 +53,8 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis
private var ringtoneManager: RingtoneManager? = null
private lateinit var prefs: Preferences
private var widgetUpdater: WidgetUpdater? = null
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RINGTONE_REQUEST_CODE) {
ringtoneManager!!.update(data)

View File

@@ -24,6 +24,7 @@ import androidx.appcompat.app.AppCompatActivity
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.models.HabitMatcher
import org.isoron.uhabits.utils.applyRootViewInsets
class EditSettingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
@@ -32,7 +33,7 @@ class EditSettingActivity : AppCompatActivity() {
val habits = app.component.habitList.getFiltered(
HabitMatcher(
isArchivedAllowed = false,
isCompletedAllowed = true,
isCompletedAllowed = true
)
)
AndroidThemeSwitcher(this, app.component.preferences).apply()
@@ -43,8 +44,9 @@ class EditSettingActivity : AppCompatActivity() {
context = this,
habitList = app.component.habitList,
onSave = controller::onSave,
args = args,
args = args
)
view.applyRootViewInsets()
setContentView(view)
}
}

View File

@@ -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)
}

View File

@@ -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)
}
}
}

View File

@@ -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<String, Any?>,
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)
}

View File

@@ -30,7 +30,7 @@ class AndroidDatabaseOpener @Inject constructor() : DatabaseOpener {
db = SQLiteDatabase.openDatabase(
file.absolutePath,
null,
SQLiteDatabase.OPEN_READWRITE,
SQLiteDatabase.OPEN_READWRITE
),
file = file
)

View File

@@ -25,5 +25,6 @@ import dagger.Provides
@Module
class ActivityContextModule(
@get:Provides
@get:ActivityContext val context: Context
@get:ActivityContext
val context: Context
)

View File

@@ -26,5 +26,6 @@ import dagger.Provides
class AppContextModule(
@get:Provides
@get:AppContext
@param:AppContext val context: Context
@param:AppContext
val context: Context
)

View File

@@ -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)
}

View File

@@ -25,6 +25,7 @@ import android.app.AlarmManager.RTC_WAKEUP
import android.app.PendingIntent
import android.content.Context
import android.content.Context.ALARM_SERVICE
import android.os.Build
import android.util.Log
import org.isoron.uhabits.core.AppScope
import org.isoron.uhabits.core.models.Habit
@@ -56,6 +57,10 @@ class IntentScheduler
)
return SchedulerResult.IGNORED
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !manager.canScheduleExactAlarms()) {
Log.e("IntentScheduler", "No permission to schedule exact alarms")
return SchedulerResult.IGNORED
}
manager.setExactAndAllowWhileIdle(alarmType, timestamp, intent)
return SchedulerResult.OK
}

Some files were not shown because too many files have changed in this diff Show More