Compare commits

..

11 Commits

512 changed files with 37604 additions and 12183 deletions

6
.github/dependabot.yml vendored Normal file
View File

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

View File

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

1
.gitignore vendored
View File

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

View File

@@ -1,41 +1,5 @@
# Changelog
## [2.2.0] -- 2024-01-30
### Added
- Add support for Android 14 (@iSoron, @hiqua)
- Allow user to change app language (@leondzn)
### Fixed
- Implement workaround to make notifications non-dismissible in Android 14 (@iSoron, #1872)
- Fix splash screen background color in dark mode (@SIKV, #1888)
## [2.1.3] -- 2023-08-28
### Fixed
- Use text input on Samsung devices (@iSoron, #1719)
- Prevent crash if alarm permission is revoked (@iSoron)
- Adjust widget colors (@iSoron)
- Fix bug preventing screens from updating at midnight (@iSoron)
- Fix skip button in locales that use comma instead of dot (@iSoron, #1721)
## [2.1.2] -- 2023-05-26
### Fixed
- Fix bug that caused widget to enter checkmark on wrong date (@iSoron, #1541)
- 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)
## [2.1.0] -- 2022-09-10
### Added
- Allow user to add notes to specific dates (@vbh, #1103)

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 alt="Build & Test" src="https://github.com/iSoron/uhabits/workflows/Build%20&%20Test/badge.svg" />
<img src="https://github.com/iSoron/uhabits/workflows/Build%20&%20Test/badge.svg" />
</a>
<a href="https://github.com/iSoron/uhabits/releases/latest">
<img alt="release" src="https://img.shields.io/github/v/release/iSoron/uhabits" />
<img src="https://img.shields.io/github/v/release/iSoron/uhabits" />
</a>
<a href="https://github.com/iSoron/uhabits/discussions">
<img alt="GitHub" src="https://img.shields.io/badge/GitHub-Discussions-%23fc4ebc" />
<img 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/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>
<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>
</p>
## Screenshots
@@ -32,23 +32,32 @@ source.
## Features
* **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>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.
* **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>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.
* **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>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.
* **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>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.
* **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>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.
* **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>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.
* **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>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.
* **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>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).
* **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.
* <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.
## Installing
@@ -85,7 +94,7 @@ contribute, even if you are not a software developer.
## License
<img align="right" alt="GPL v3" src="https://www.gnu.org/graphics/gplv3-88x31.png">
<img align="right" src="https://www.gnu.org/graphics/gplv3-88x31.png">
Copyright (C) 2016-2021 Álinson Santos Xavier <isoron@gmail.com>

View File

@@ -1,10 +1,11 @@
plugins {
val kotlinVersion = "2.1.10"
id("com.android.application") version "8.8.0" apply (false)
val kotlinVersion = "1.7.10"
id("com.android.application") version ("7.3.0-rc01") apply (false)
id("org.jetbrains.kotlin.android") version kotlinVersion apply (false)
id("org.jetbrains.kotlin.kapt") version kotlinVersion apply (false)
id("org.jetbrains.kotlin.android.extensions") version kotlinVersion apply (false)
id("org.jetbrains.kotlin.multiplatform") version kotlinVersion apply (false)
id("org.jlleitschuh.gradle.ktlint") version "11.6.1"
id("org.jlleitschuh.gradle.ktlint") version "11.0.0"
}
apply {
@@ -18,6 +19,5 @@ allprojects {
maven(url = "https://plugins.gradle.org/m2/")
maven(url = "https://oss.sonatype.org/content/repositories/snapshots/")
maven(url = "https://jitpack.io")
maven(url = "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-js-wrappers/") // Repository for kotlin-css-jvm old versions, now that the Gradle Plugin Portal no longer brings these in by mirroring JCenter
}
}

View File

@@ -64,7 +64,6 @@ fail() {
core_build() {
log_info "Building uhabits-core..."
$GRADLE ktlintCheck || fail
$GRADLE lintDebug || fail
$GRADLE :uhabits-core:build || fail
}
@@ -182,7 +181,7 @@ android_test() {
OUT_INSTRUMENT=${ANDROID_OUTPUTS_DIR}/instrument-${API}.txt
OUT_LOGCAT=${ANDROID_OUTPUTS_DIR}/logcat-${API}.txt
FAILED_TESTS=""
for i in {1..10}; do
for i in {1..5}; do
log_info "Running $size instrumented tests (attempt $i)..."
$ADB shell am instrument \
-r -e coverage true -e size "$size" $FAILED_TESTS \
@@ -218,28 +217,20 @@ android_test_parallel() {
(
LOG=build/android-test-$API.log
log_info "API $API: Running tests..."
android_test $API 1>$LOG 2>&1
ret_code=$?
if [ $ret_code = 0 ]; then
if android_test $API 1>$LOG 2>&1; 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
success=0
RET_CODE=0
for pid in $PIDS; do
wait $pid
ret_code=$?
if [ $ret_code != 0 ]; then
success=1
fi
echo pid=$pid ret_code=$ret_code success=$success
wait $pid || RET_CODE=1
done
# Print all logs
@@ -249,7 +240,7 @@ android_test_parallel() {
echo "::endgroup::"
done
return $success
return $RET_CODE
}
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,11 +79,13 @@ 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 `./uhabits-android/build/outputs/apk/debug/uhabits-android-debug.apk`, 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 the following, 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,6 +12,17 @@
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

@@ -2,25 +2,51 @@
Loop Habit Tracker has a fairly large number of automated tests to reduce the chance of bugs being silently introduced in our code base. The tests are divided into three categories:
- **Unit tests:** These tests run very quickly on the developer's computer, inside a JVM, and do not need an Android emulator or device. They typically test the correctness of core functions of the application, such as the computation of scores and streaks.
- **Instrumented tests:** These tests require an Android emulator or device. _Medium_ instrumented tests are still quite fast to run, since only individual classes are tested. The app itself does not need to be launched. Examples include _view tests_, which render our custom views on the device and compare them against prerendered images. _Large_ instrumented tests launch the application on an Android emulator and interact with it by touching the screen, much like a regular user.
* **Small tests:** These tests run very quickly on the developer's computer, inside a JVM, and do not need an Android emulator or device. They typically test the correctness of core functions of the application, such as the computation of scores and streaks.
* **Medium tests:** These tests require an Android emulator or device, but they are still quite fast to run, since only individual classes are tested. The app itself does not need to be launched. Examples include *view tests*, which render our custom views on the device and compare them against prerendered images.
* **Large tests:** These are end-to-end tests, which launch the application on an Android emulator and interact with it by touching the screen, much like a regular user.
## Running unit tests
## Running small tests
Unit tests can be launched by running `./gradlew test` or by right-clicking a particular class/method in Android Studio and selecting "Run testMethod()" or "Run ClassTest". An alternative way is to use `build.sh`, the script used by our continuous integration server. By running `./build.sh build`, the script will automatically build and run all small tests.
Small tests can be launched by running `./gradlew test` or by right-clicking a particular class/method in Android Studio and selecting "Run testMethod()" or "Run ClassTest". An alternative way is to use `build.sh`, the script used by our continuous integration server. By running `./build.sh build`, the script will automatically build and run all small tests.
## Running instrumented tests
## Running medium tests
To run medium tests, it is recommended to use the `build.sh` script.
To run medium tests, it is recommended to use the `build.sh` script:
1. Run `./build.sh android-setup API` to create the emulator, where `API` is the desired API level.
2. Run `./build.sh android-tests API` to run the tests on a single API.
3. Run `./build.sh android-tests-parallel API API...` to run the tests on multiple APIs in parallel.
./build.sh build
./build.sh medium-tests
Note that instrumented tests are designed to run on a clean install, inside an emulator. They will not work on actual devices. All tests are also designed for a particular screen size, namely the Nexus 4 configuration (4.7" 768x1280 xhdpi), and a particular locale, namely English (US). Furthermore:
- No additional apps should be installed on the device;
- The homescreen must look exactly like it was when the emulator was originally created, with no additional icons or widgets;
- All animations must be manually disabled.
For this script to succeed, make sure that an emulator is currently running, or that a device (with developer mode activated) is connected via USB.
If there are failing view tests (that is, if some custom views do not render exactly like the prerendered images we have), then both the actual and expected images will be automatically downloaded from the device to the folder `uhabits-android/build/outputs`. After verifying the differences, if you feel that the actual images are actually fine and should replace the prerendered ones, then run `./build.sh android-accept-images`.
**WARNING!** This script will uninstall the app prior to testing it, and therefore delete all user data!
If there are failing view tests (that is, if some custom views do not render exactly like the prerendered images we have), then the script `./build.sh fetch-images` can be used to download both the actual and the expected images from the device. The images will be downloaded from the device into the folder `tmp/`. After verifying the differences, if you feel that the actual images are actually fine and should replace the prerendered ones, then run `./build.sh accept-images`.
## Running large tests
Large tests are significantly more complicated to run. In particular, they require:
* An Android emulator; they will **not** work on actual devices;
* A vanilla x86 AOSP image; they will **not** work with Google API images;
* A particular screen size, namely the Nexus 4 configuration on Android Studio (4.7 768x1280 xhdpi);
* A particular locale, namely English (US).
Furthermore:
* No additional apps should be installed on the device;
* The homescreen must look exactly like it was when the emulator was originally created, with no additional icons or widgets;
* Developer mode must be activated, and all animations must be manually disabled.
Only the following Android versions are supported by our test suite:
* Android 7.0 (API 24)
* Android 7.1.1 (API 25)
* Android 8.0 (API 26)
* Android 8.1 (API 27)
* Android 9.0 (API 28)
* Android 10.0 (API 29)
After creating an emulator and configuring it exactly as described above, launch it, wait for it to finish booting up, then run `./build.sh large-tests`. As mentioned before, this script will uninstall the app before testing it, and therefore will delete all the user data.

View File

@@ -3,6 +3,3 @@ org.gradle.daemon=true
org.gradle.jvmargs=-Xms2048m -Xmx2048m
android.useAndroidX=true
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

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

View File

@@ -10,4 +10,4 @@ pluginManagement {
}
}
include(":uhabits-android", ":uhabits-core")
include(":uhabits-android", ":uhabits-core", ":uhabits-server")

30
tools/androidStringsToKt.sh Executable file
View File

@@ -0,0 +1,30 @@
#!/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 "}"

46
tools/convertAllStrings.sh Executable file
View File

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

View File

@@ -18,9 +18,11 @@
*/
plugins {
id("com.android.application") version "8.8.0"
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")
}
@@ -28,28 +30,15 @@ tasks.compileLint {
dependsOn("updateTranslators")
}
/*
Added on top of kotlinOptions to work around this issue:
https://youtrack.jetbrains.com/issue/KTIJ-24311/task-current-target-is-17-and-kaptGenerateStubsProductionDebugKotlin-task-current-target-is-1.8-jvm-target-compatibility-should#focus=Comments-27-6798448.0-0
Updating gradle might fix this, so try again in the future to remove this and run:
./gradlew --rerun-tasks :uhabits-android:kaptGenerateStubsReleaseKotlin
If this doesn't produce any warning, try to remove it.
*/
kotlin {
jvmToolchain(11)
}
android {
namespace = "org.isoron.uhabits"
compileSdk = 35
// compileSdkPreview = "VanillaIceCream"
compileSdk = 32
defaultConfig {
versionCode = 20200
versionName = "2.2.0"
versionCode = 20100
versionName = "2.1.0"
minSdk = 28
targetSdk = 35
targetSdk = 31
applicationId = "org.isoron.uhabits"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
@@ -81,28 +70,21 @@ android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
targetCompatibility(JavaVersion.VERSION_11)
sourceCompatibility(JavaVersion.VERSION_11)
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
targetCompatibility(JavaVersion.VERSION_1_8)
sourceCompatibility(JavaVersion.VERSION_1_8)
}
buildFeatures {
viewBinding = true
}
lint {
abortOnError = false
}
}
dependencies {
val daggerVersion = "2.51.1"
val kotlinVersion = "2.1.10"
val kxCoroutinesVersion = "1.10.1"
val daggerVersion = "2.43.2"
val kotlinVersion = "1.7.10"
val kxCoroutinesVersion = "1.6.4"
val ktorVersion = "1.6.8"
val espressoVersion = "3.6.1"
val espressoVersion = "3.4.0"
androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion")
androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion")
@@ -110,17 +92,17 @@ dependencies {
androidTestImplementation("com.linkedin.dexmaker:dexmaker-mockito:2.28.3")
androidTestImplementation("io.ktor:ktor-client-mock:$ktorVersion")
androidTestImplementation("io.ktor:ktor-jackson:$ktorVersion")
androidTestImplementation("androidx.annotation:annotation:1.7.1")
androidTestImplementation("androidx.test.ext:junit:1.2.1")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
androidTestImplementation("androidx.test:rules:1.6.1")
androidTestImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
androidTestImplementation("androidx.annotation:annotation:1.4.0")
androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.uiautomator:uiautomator:2.2.0")
androidTestImplementation("androidx.test:rules:1.4.0")
androidTestImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
compileOnly("javax.annotation:jsr250-api:1.0")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
implementation("com.github.AppIntro:AppIntro:6.3.1")
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:33.1.0-android")
implementation("com.google.guava:guava:31.1-android")
implementation("io.ktor:ktor-client-android:$ktorVersion")
implementation("io.ktor:ktor-client-core:$ktorVersion")
implementation("io.ktor:ktor-client-jackson:$ktorVersion")
@@ -128,20 +110,24 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$kxCoroutinesVersion")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$kxCoroutinesVersion")
implementation("androidx.appcompat:appcompat:1.7.0")
implementation("androidx.appcompat:appcompat:1.5.0")
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.12.0")
implementation("com.opencsv:opencsv:5.9")
implementation("nl.dionsegijn:konfetti-xml:2.0.2")
implementation("com.google.android.material:material:1.6.1")
implementation("com.opencsv:opencsv:5.6")
implementation(project(":uhabits-core"))
kapt("com.google.dagger:dagger-compiler:$daggerVersion")
kaptAndroidTest("com.google.dagger:dagger-compiler:$daggerVersion")
testImplementation("com.google.dagger:dagger:$daggerVersion")
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito.kotlin:mockito-kotlin:5.4.0")
testImplementation("com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0")
}
kapt {
correctErrorTypes = true
}
play {
serviceAccountCredentials.set(file("../.secret/gcp-key.json"))
track.set("alpha")
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -39,7 +39,6 @@ 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,22 +153,18 @@ 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,6 +19,7 @@
package org.isoron.uhabits
import com.nhaarman.mockitokotlin2.mock
import dagger.Component
import dagger.Module
import dagger.Provides
@@ -34,7 +35,6 @@ import org.isoron.uhabits.inject.ActivityScope
import org.isoron.uhabits.inject.HabitModule
import org.isoron.uhabits.inject.HabitsActivityModule
import org.isoron.uhabits.inject.HabitsApplicationComponent
import org.mockito.kotlin.mock
@Module
class TestModule {

View File

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

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

View File

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

View File

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

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,6 +20,9 @@ package org.isoron.uhabits.activities.habits.list.views
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import com.nhaarman.mockitokotlin2.doReturn
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.whenever
import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.MatcherAssert.assertThat
import org.isoron.uhabits.BaseViewTest
@@ -27,9 +30,6 @@ import org.isoron.uhabits.core.ui.screens.habits.list.HintList
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@MediumTest

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,11 +33,9 @@ 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">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.isoron.uhabits">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.BROADCAST_CLOSE_SYSTEM_DIALOGS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:name=".HabitsApplication"
@@ -30,7 +30,6 @@
android:backupAgent=".HabitsBackupAgent"
android:icon="@mipmap/ic_launcher"
android:label="@string/main_activity_title"
android:localeConfig="@xml/locales_config"
android:supportsRtl="true"
android:theme="@style/AppBaseTheme">
@@ -80,6 +79,14 @@
android:value=".activities.habits.list.ListHabitsActivity" />
</activity>
<activity
android:name=".activities.sync.SyncActivity"
android:label="@string/device_sync">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activities.sync.SyncActivity" />
</activity>
<activity
android:name=".activities.intro.IntroActivity"
android:label=""
@@ -271,7 +278,7 @@
<!-- Locale/Tasker -->
<receiver
android:name=".automation.FireSettingReceiver"
android:exported="true">
android:exported="false">
<intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" />
</intent-filter>

View File

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

View File

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

View File

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

View File

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

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,11 +140,8 @@ 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,14 +26,13 @@ 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))
@@ -44,7 +43,7 @@ class AboutView(
toolbar = binding.toolbar,
color = PaletteColor(11),
title = resources.getString(R.string.about),
theme = currentTheme()
theme = currentTheme(),
)
val version = resources.getString(R.string.version_n)
binding.tvContributors.setOnClickListener { screen.showCodeContributorsWebsite() }
@@ -55,6 +54,5 @@ 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,63 +20,109 @@
package org.isoron.uhabits.activities.common.dialogs
import android.app.Dialog
import android.os.Bundle
import android.content.Context
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.getCenter
import org.isoron.uhabits.utils.dimBehind
import org.isoron.uhabits.utils.dismissCurrentAndShow
import org.isoron.uhabits.utils.dp
import org.isoron.uhabits.utils.sres
class CheckmarkDialog : AppCompatDialogFragment() {
var onToggle: (Int, String, Float, Float) -> Unit = { _, _, _, _ -> }
const val POPUP_WIDTH = 4 * 48f + 16f
const val POPUP_HEIGHT = 48f * 2.5f + 8f
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")
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,
) {
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() {
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(requireContext())
it.typeface = getFontAwesome(context)
}
view.notes.setText(requireArguments().getString("notes")!!)
}
private fun hideDisabledButtons() {
if (!prefs.isSkipEnabled) view.skipBtn.visibility = GONE
if (!prefs.areQuestionMarksEnabled) view.unknownBtn.visibility = GONE
view.booleanButtons.visibility = VISIBLE
val dialog = Dialog(requireContext())
}
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)
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) {
val notes = view.notes.text.toString().trim()
val location = view.yesBtn.getCenter()
onToggle(v, notes, location.x, location.y)
requireDialog().dismiss()
this.value = v
save()
}
view.yesBtn.setOnClickListener { onClick(YES_MANUAL) }
view.noBtn.setOnClickListener { onClick(NO) }
view.skipBtn.setOnClickListener { onClick(SKIP) }
view.unknownBtn.setOnClickListener { onClick(UNKNOWN) }
view.notes.setOnEditorActionListener { v, actionId, event ->
onClick(requireArguments().getInt("value"))
true
}
dialog.setCanceledOnTouchOutside(true)
dialog.dimBehind()
dialog.dismissCurrentAndShow()
}
return dialog
fun save() {
onToggle(value, view.notes.text.toString().trim())
dialog.dismiss()
}
}

View File

@@ -19,7 +19,6 @@
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
@@ -40,7 +39,7 @@ class ColorPickerDialogFactory @Inject constructor(@param:ActivityContext privat
res.getPalette(),
androidColor,
4,
SIZE_SMALL
com.android.colorpicker.ColorPickerDialog.SIZE_SMALL
)
return dialog
}

View File

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

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

@@ -1,121 +0,0 @@
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, Float, Float) -> Unit = { _, _, _, _ -> }
var onDismiss: () -> Unit = {}
private var originalNotes: String = ""
private var originalValue: Double = 0.0
private lateinit var view: CheckmarkPopupBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val appComponent = (requireActivity().application as HabitsApplication).component
val prefs = appComponent.preferences
view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context))
arrayOf(view.yesBtn, view.skipBtn).forEach {
it.setTextColor(requireArguments().getInt("color"))
}
arrayOf(view.noBtn, view.unknownBtn).forEach {
it.setTextColor(view.root.sres.getColor(R.attr.contrast60))
}
arrayOf(view.yesBtn, view.noBtn, view.skipBtn, view.unknownBtn).forEach {
it.typeface = InterfaceUtils.getFontAwesome(requireContext())
}
if (!prefs.isSkipEnabled) view.skipBtnNumber.visibility = View.GONE
view.numberButtons.visibility = View.VISIBLE
fixDecimalSeparator(view)
originalNotes = requireArguments().getString("notes")!!
originalValue = requireArguments().getDouble("value")
view.notes.setText(originalNotes)
view.value.setText(
when {
originalValue < 0.01 -> "0"
else -> DecimalFormat("#.##").format(originalValue)
}
)
view.value.setOnKeyListener { _, keyCode, event ->
if (event.action == MotionEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) {
save()
return@setOnKeyListener true
}
return@setOnKeyListener false
}
view.saveBtn.setOnClickListener {
save()
}
view.skipBtnNumber.setOnClickListener {
view.value.setText(DecimalFormat("#.###").format((Entry.SKIP.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, location.x, location.y)
requireDialog().dismiss()
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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,9 +181,8 @@ 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)
@@ -197,14 +196,12 @@ 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,7 +58,6 @@ class RingView : View {
private var em = 0f
private var text: String?
private var textSize: Float
private var isStrokedTextEnabled: Boolean = false
private var enableFontAwesome = false
private var internalDrawingCache: Bitmap? = null
private var cacheCanvas: Canvas? = null
@@ -132,10 +131,6 @@ class RingView : View {
invalidate()
}
fun setIsStrokedTextEnabled(isStroked: Boolean) {
this.isStrokedTextEnabled = isStroked
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
val activeCanvas: Canvas?
@@ -153,23 +148,13 @@ 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,6 +22,7 @@ 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
@@ -34,6 +35,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
import com.android.datetimepicker.time.RadialPickerLayout
import com.android.datetimepicker.time.TimePickerDialog
import kotlinx.android.synthetic.main.activity_edit_habit.nameInput
import kotlinx.android.synthetic.main.activity_edit_habit.notesInput
import kotlinx.android.synthetic.main.activity_edit_habit.questionInput
import kotlinx.android.synthetic.main.activity_edit_habit.targetInput
import kotlinx.android.synthetic.main.activity_edit_habit.unitInput
import org.isoron.platform.gui.toInt
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
@@ -52,8 +58,7 @@ 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.applyRootViewInsets
import org.isoron.uhabits.utils.applyToolbarInsets
import org.isoron.uhabits.utils.ColorUtils
import org.isoron.uhabits.utils.dismissCurrentAndShow
import org.isoron.uhabits.utils.formatTime
import org.isoron.uhabits.utils.toFormattedString
@@ -94,8 +99,6 @@ class EditHabitActivity : AppCompatActivity() {
themeSwitcher.apply()
binding = ActivityEditHabitBinding.inflate(layoutInflater)
binding.root.applyRootViewInsets()
binding.toolbar.applyToolbarInsets()
setContentView(binding.root)
if (intent.hasExtra("habitId")) {
@@ -268,9 +271,9 @@ class EditHabitActivity : AppCompatActivity() {
habit.copyFrom(original)
}
habit.name = binding.nameInput.text.trim().toString()
habit.question = binding.questionInput.text.trim().toString()
habit.description = binding.notesInput.text.trim().toString()
habit.name = nameInput.text.trim().toString()
habit.question = questionInput.text.trim().toString()
habit.description = notesInput.text.trim().toString()
habit.color = color
if (reminderHour >= 0) {
habit.reminder = Reminder(reminderHour, reminderMin, reminderDays)
@@ -280,9 +283,9 @@ class EditHabitActivity : AppCompatActivity() {
habit.frequency = Frequency(freqNum, freqDen)
if (habitType == HabitType.NUMERICAL) {
habit.targetValue = binding.targetInput.text.toString().toDouble()
habit.targetValue = targetInput.text.toString().toDouble()
habit.targetType = targetType
habit.unit = binding.unitInput.text.trim().toString()
habit.unit = unitInput.text.trim().toString()
}
habit.type = habitType
@@ -305,13 +308,13 @@ class EditHabitActivity : AppCompatActivity() {
private fun validate(): Boolean {
var isValid = true
if (binding.nameInput.text.isEmpty()) {
binding.nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
if (nameInput.text.isEmpty()) {
nameInput.error = getFormattedValidationError(R.string.validation_cannot_be_blank)
isValid = false
}
if (habitType == HabitType.NUMERICAL) {
if (binding.targetInput.text.isEmpty()) {
binding.targetInput.error = getString(R.string.validation_cannot_be_blank)
if (targetInput.text.isEmpty()) {
targetInput.error = getString(R.string.validation_cannot_be_blank)
isValid = false
}
}
@@ -354,7 +357,8 @@ class EditHabitActivity : AppCompatActivity() {
androidColor = themeSwitcher.currentTheme.color(color).toInt()
binding.colorButton.backgroundTintList = ColorStateList.valueOf(androidColor)
if (!themeSwitcher.isNightMode) {
window.statusBarColor = androidColor
val darkerAndroidColor = ColorUtils.mixColors(Color.BLACK, androidColor, 0.15f)
window.statusBarColor = darkerAndroidColor
binding.toolbar.setBackgroundColor(androidColor)
}
}

View File

@@ -19,17 +19,12 @@
package org.isoron.uhabits.activities.habits.list
import android.Manifest.permission.POST_NOTIFICATIONS
import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts.RequestPermission
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat.checkSelfPermission
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import org.isoron.uhabits.BaseExceptionHandler
@@ -45,8 +40,6 @@ 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 {
@@ -62,16 +55,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
lateinit var midnightTimer: MidnightTimer
private val scope = CoroutineScope(Dispatchers.Main)
private var permissionAlreadyRequested = false
private val permissionLauncher =
registerForActivityResult(RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
scheduleReminders()
} else {
Log.i("ListHabitsActivity", "POST_NOTIFICATIONS denied")
}
}
private lateinit var menu: ListHabitsMenu
override fun onQuestionMarksChanged() {
@@ -101,7 +84,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
menu = component.listHabitsMenu
Thread.setDefaultUncaughtExceptionHandler(BaseExceptionHandler(this))
component.listHabitsBehavior.onStartup()
rootView.applyRootViewInsets()
setContentView(rootView)
}
@@ -109,7 +91,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
midnightTimer.onPause()
screen.onDetached()
adapter.cancelRefresh()
dismissCurrentDialog()
super.onPause()
}
@@ -118,26 +99,6 @@ 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()
@@ -153,10 +114,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
super.onResume()
}
private fun scheduleReminders() {
appComponent.reminderScheduler.scheduleAll()
}
override fun onCreateOptionsMenu(m: Menu): Boolean {
menu.onCreate(menuInflater, m)
return true
@@ -167,7 +124,6 @@ class ListHabitsActivity : AppCompatActivity(), Preferences.Listener {
return menu.onItemSelected(item)
}
@Deprecated("Deprecated in Java")
override fun onActivityResult(request: Int, result: Int, data: Intent?) {
super.onActivityResult(request, result, data)
screen.onResult(request, result, data)

View File

@@ -23,7 +23,6 @@ import android.content.Context
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.widget.FrameLayout
import android.widget.RelativeLayout
import nl.dionsegijn.konfetti.xml.KonfettiView
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.common.views.ScrollableChart
import org.isoron.uhabits.activities.common.views.TaskProgressBar
@@ -70,9 +69,6 @@ class ListHabitsRootView @Inject constructor(
val listView: HabitCardListView = habitCardListViewFactory.create()
val llEmpty = EmptyListView(context)
val tbar = buildToolbar()
val konfettiView = KonfettiView(context).apply {
translationZ = 10f
}
val progressBar = TaskProgressBar(context, runner)
val hintView: HintView
val header = HeaderView(context, preferences, midnightTimer)
@@ -84,7 +80,6 @@ class ListHabitsRootView @Inject constructor(
val rootView = RelativeLayout(context).apply {
background = sres.getDrawable(R.attr.windowBackgroundColor)
addAtTop(konfettiView)
addAtTop(tbar)
addBelow(header, tbar)
addBelow(listView, header, height = MATCH_PARENT)
@@ -99,7 +94,7 @@ class ListHabitsRootView @Inject constructor(
title = resources.getString(R.string.main_activity_title),
color = PaletteColor(17),
displayHomeAsUpEnabled = false,
theme = currentTheme()
theme = currentTheme(),
)
addView(rootView, MATCH_PARENT, MATCH_PARENT)
listAdapter.setListView(listView)

View File

@@ -22,18 +22,14 @@ 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.CheckmarkDialog
import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup
import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
import org.isoron.uhabits.activities.common.dialogs.NumberDialog
import org.isoron.uhabits.activities.common.dialogs.NumberPopup
import org.isoron.uhabits.activities.habits.edit.HabitTypeDialog
import org.isoron.uhabits.activities.habits.list.views.HabitCardListAdapter
import org.isoron.uhabits.core.commands.ArchiveHabitsCommand
@@ -66,7 +62,6 @@ import org.isoron.uhabits.intents.IntentFactory
import org.isoron.uhabits.tasks.ExportDBTaskFactory
import org.isoron.uhabits.tasks.ImportDataTask
import org.isoron.uhabits.tasks.ImportDataTaskFactory
import org.isoron.uhabits.utils.ColorUtils
import org.isoron.uhabits.utils.copyTo
import org.isoron.uhabits.utils.currentTheme
import org.isoron.uhabits.utils.dismissCurrentAndShow
@@ -76,7 +71,6 @@ import org.isoron.uhabits.utils.showSendEmailScreen
import org.isoron.uhabits.utils.showSendFileScreen
import java.io.File
import java.io.IOException
import java.util.concurrent.TimeUnit
import javax.inject.Inject
const val RESULT_IMPORT_DATA = 101
@@ -101,7 +95,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,
@@ -223,28 +217,6 @@ class ListHabitsScreen
activity.showSendFileScreen(filename)
}
override fun showConfetti(color: PaletteColor, x: Float, y: Float) {
val baseColor = themeSwitcher.currentTheme!!.color(color).toInt()
rootView.get().konfettiView.start(
Party(
speed = 0f,
maxSpeed = 16f,
damping = 0.9f,
spread = 360,
angle = 0,
colors = listOf(
ColorUtils.changeHue(baseColor, 180f),
ColorUtils.changeHue(baseColor, 20f),
ColorUtils.changeHue(baseColor, -20f),
baseColor
),
position = Position.Absolute(x, y),
emitter = Emitter(duration = 25, TimeUnit.MILLISECONDS).max(25),
timeToLive = 0
)
)
}
override fun showSettingsScreen() {
val intent = intentFactory.startSettingsActivity(activity)
activity.startActivityForResult(intent, REQUEST_SETTINGS)
@@ -261,14 +233,17 @@ class ListHabitsScreen
notes: String,
callback: ListHabitsBehavior.NumberPickerCallback
) {
val fm = (context as AppCompatActivity).supportFragmentManager
val dialog = NumberDialog()
dialog.arguments = Bundle().apply {
putDouble("value", value)
putString("notes", notes)
val view = rootView.get()
NumberPopup(
context = context,
prefs = preferences,
anchor = view,
notes = notes,
value = value,
).apply {
onToggle = { value, notes -> callback.onNumberPicked(value, notes) }
show()
}
dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) }
dialog.dismissCurrentAndShow(fm, "numberDialog")
}
override fun showCheckmarkPopup(
@@ -277,16 +252,18 @@ class ListHabitsScreen
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback
) {
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)
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()
}
dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) }
dialog.dismissCurrentAndShow(fm, "checkmarkDialog")
}
private fun getExecuteString(command: Command): String? {
@@ -348,11 +325,8 @@ 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,11 +60,8 @@ 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,6 +44,8 @@ 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,
@@ -77,7 +79,7 @@ class CheckmarkButtonView(
invalidate()
}
var onToggle: (Int, String) -> Unit = { _, _ -> }
var onToggle: (Int, String, Long) -> Unit = { _, _, _ -> }
var onEdit: () -> Unit = { }
@@ -88,31 +90,25 @@ class CheckmarkButtonView(
setOnLongClickListener(this)
}
fun performToggle() {
fun performToggle(delay: Long) {
value = Entry.nextToggleValue(
value = value,
isSkipEnabled = preferences.isSkipEnabled,
areQuestionMarksEnabled = preferences.areQuestionMarksEnabled
)
onToggle(value, notes)
onToggle(value, notes, delay)
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
invalidate()
}
override fun onClick(v: View) {
if (preferences.isShortToggleEnabled) {
performToggle()
} else {
onEdit()
}
if (preferences.isShortToggleEnabled) performToggle(TOGGLE_DELAY_MILLIS)
else onEdit()
}
override fun onLongClick(v: View): Boolean {
if (preferences.isShortToggleEnabled) {
onEdit()
} else {
performToggle()
}
if (preferences.isShortToggleEnabled) onEdit()
else performToggle(TOGGLE_DELAY_MILLIS)
return true
}
@@ -146,11 +142,8 @@ 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
}
@@ -158,11 +151,8 @@ 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) -> Unit = { _, _, _ -> }
var onToggle: (Timestamp, Int, String, Long) -> Unit = { _, _, _, _ -> }
set(value) {
field = value
setupButtons()
@@ -89,7 +89,7 @@ class CheckmarkPanelView(
else -> ""
}
button.color = color
button.onToggle = { value, notes -> onToggle(timestamp, value, notes) }
button.onToggle = { value, notes, delay -> onToggle(timestamp, value, notes, delay) }
button.onEdit = { onEdit(timestamp) }
}
}

View File

@@ -156,11 +156,10 @@ 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,7 +20,6 @@
package org.isoron.uhabits.activities.habits.list.views
import android.content.Context
import android.graphics.PointF
import android.graphics.text.LineBreaker.BREAK_STRATEGY_BALANCED
import android.os.Build
import android.os.Build.VERSION.SDK_INT
@@ -58,6 +57,13 @@ 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,
@@ -130,6 +136,7 @@ class HabitCardView(
private var scoreRing: RingView
private var currentToggleTaskId = 0
private var queuedToggles = mutableListOf<DelayedToggle>()
init {
scoreRing = RingView(context).apply {
@@ -153,18 +160,11 @@ class HabitCardView(
}
checkmarkPanel = checkmarkPanelFactory.create().apply {
onToggle = { timestamp, value, notes ->
triggerRipple(timestamp)
val location = getAbsoluteButtonLocation(timestamp)
onToggle = { timestamp, value, notes, delay ->
if (delay > 0) triggerRipple(timestamp)
habit?.let {
behavior.onToggle(
it,
timestamp,
value,
notes,
location.x,
location.y
)
val taskId = queueToggle(it, timestamp, value, notes);
{ runPendingToggles(taskId) }.delay(delay)
}
}
onEdit = { timestamp ->
@@ -205,6 +205,25 @@ 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) }
@@ -217,27 +236,12 @@ class HabitCardView(
}
fun triggerRipple(timestamp: Timestamp) {
val location = getRelativeButtonLocation(timestamp)
triggerRipple(location.x, location.y)
}
private fun getRelativeButtonLocation(timestamp: Timestamp): PointF {
val today = DateUtils.getTodayWithOffset()
val offset = timestamp.daysUntil(today) - dataOffset
val button = checkmarkPanel.buttons[offset]
val y = button.height / 2.0f
val x = checkmarkPanel.x + button.x + (button.width / 2).toFloat()
return PointF(x, y)
}
private fun getAbsoluteButtonLocation(timestamp: Timestamp): PointF {
val containerLocation = IntArray(2)
this.getLocationOnScreen(containerLocation)
val relButtonLocation = getRelativeButtonLocation(timestamp)
return PointF(
containerLocation[0].toFloat() + relButtonLocation.x,
containerLocation[1].toFloat() - relButtonLocation.y
)
triggerRipple(x, y)
}
override fun onAttachedToWindow() {
@@ -251,6 +255,7 @@ class HabitCardView(
}
private fun copyAttributesFrom(h: Habit) {
fun getActiveColor(habit: Habit): Int {
return when (habit.isArchived) {
true -> sres.getColor(R.attr.contrast60)
@@ -296,6 +301,7 @@ class HabitCardView(
}
private fun updateBackground(isSelected: Boolean) {
val background = when (isSelected) {
true -> R.drawable.selected_box
false -> R.drawable.ripple

View File

@@ -124,24 +124,19 @@ 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).uppercase().split("\n")
val lines = DateUtils.formatHeaderDate(day).toUpperCase().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.CheckmarkDialog
import org.isoron.uhabits.activities.common.dialogs.CheckmarkPopup
import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog
import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog
import org.isoron.uhabits.activities.common.dialogs.NumberDialog
import org.isoron.uhabits.activities.common.dialogs.NumberPopup
import org.isoron.uhabits.core.commands.Command
import org.isoron.uhabits.core.commands.CommandRunner
import org.isoron.uhabits.core.models.Habit
@@ -49,10 +49,8 @@ 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
@@ -89,7 +87,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
habit = habit,
habitList = habitList,
preferences = preferences,
screen = screen
screen = screen,
)
view = ShowHabitView(this)
@@ -100,17 +98,16 @@ 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)
}
@@ -132,7 +129,6 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
}
override fun onPause() {
dismissCurrentDialog()
commandRunner.removeListener(this)
super.onPause()
}
@@ -152,7 +148,7 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
ShowHabitPresenter.buildState(
habit = habit,
preferences = preferences,
theme = themeSwitcher.currentTheme
theme = themeSwitcher.currentTheme,
)
)
}
@@ -174,32 +170,41 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener {
override fun showNumberPopup(
value: Double,
notes: String,
preferences: Preferences,
callback: ListHabitsBehavior.NumberPickerCallback
) {
val dialog = NumberDialog()
dialog.arguments = Bundle().apply {
putDouble("value", value)
putString("notes", notes)
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()
}
dialog.onToggle = { v, n, x, y -> callback.onNumberPicked(v, n, x, y) }
dialog.dismissCurrentAndShow(supportFragmentManager, "numberDialog")
}
override fun showCheckmarkPopup(
selectedValue: Int,
notes: String,
preferences: Preferences,
color: PaletteColor,
callback: ListHabitsBehavior.CheckMarkDialogCallback
) {
val theme = view.currentTheme()
val dialog = CheckmarkDialog()
dialog.arguments = Bundle().apply {
putInt("color", theme.color(color).toInt())
putInt("value", selectedValue)
putString("notes", notes)
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()
}
dialog.onToggle = { v, n, x, y -> callback.onNotesSaved(v, n, x, y) }
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,14 +25,12 @@ 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)
}
@@ -41,7 +39,7 @@ class ShowHabitView(context: Context) : FrameLayout(context) {
binding.toolbar,
title = data.title,
color = data.color,
theme = data.theme
theme = data.theme,
)
binding.subtitleCard.setState(data.subtitle)
binding.overviewCard.setState(data.overview)
@@ -54,6 +52,7 @@ 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.getDefault())).apply {
binding.chart.view = BarChart(state.theme, JavaLocalDateFormatter(Locale.US)).apply {
series = mutableListOf(state.entries.map { it.value / 1000.0 })
colors = mutableListOf(theme.color(state.color.paletteIndex))
axis = state.entries.map { it.timestamp.toLocalDate() }
@@ -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,7 +26,6 @@ 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() {
@@ -41,9 +40,8 @@ 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

@@ -22,7 +22,6 @@ import android.app.backup.BackupManager
import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.util.Log
@@ -44,7 +43,6 @@ import org.isoron.uhabits.core.utils.DateUtils.Companion.getLongWeekdayNames
import org.isoron.uhabits.notifications.AndroidNotificationTray.Companion.createAndroidNotificationChannel
import org.isoron.uhabits.notifications.RingtoneManager
import org.isoron.uhabits.utils.StyledResources
import org.isoron.uhabits.utils.startActivitySafely
import org.isoron.uhabits.widgets.WidgetUpdater
import java.util.Calendar
@@ -53,8 +51,6 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis
private var ringtoneManager: RingtoneManager? = null
private lateinit var prefs: Preferences
private var widgetUpdater: WidgetUpdater? = null
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == RINGTONE_REQUEST_CODE) {
ringtoneManager!!.update(data)
@@ -96,24 +92,16 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key ?: return false
when (key) {
"reminderSound" -> {
showRingtonePicker()
return true
}
"reminderCustomize" -> {
createAndroidNotificationChannel(requireContext())
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID)
startActivity(intent)
return true
}
"rateApp" -> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.playStoreURL)))
activity?.startActivitySafely(intent)
return true
}
if (key == "reminderSound") {
showRingtonePicker()
return true
} else if (key == "reminderCustomize") {
createAndroidNotificationChannel(requireContext())
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, requireContext().packageName)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationTray.REMINDERS_CHANNEL_ID)
startActivity(intent)
return true
}
return super.onPreferenceTreeClick(preference)
}

View File

@@ -0,0 +1,100 @@
/*
* 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.sync
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.models.PaletteColor
import org.isoron.uhabits.databinding.SyncActivityBinding
import org.isoron.uhabits.utils.setupToolbar
class SyncActivity : AppCompatActivity() {
private lateinit var binding: SyncActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val component = (application as HabitsApplication).component
val themeSwitcher = AndroidThemeSwitcher(this, component.preferences)
themeSwitcher.apply()
binding = SyncActivityBinding.inflate(LayoutInflater.from(this))
binding.root.setupToolbar(
toolbar = binding.toolbar,
title = resources.getString(R.string.device_sync),
color = PaletteColor(11),
theme = themeSwitcher.currentTheme,
)
binding.generateButton.setOnClickListener { onGenerateCode() }
binding.enterButton.setOnClickListener {
val et = EditText(this)
AlertDialog.Builder(this)
.setTitle(R.string.sync_code)
.setView(et)
.setPositiveButton(R.string.save) { _, _ ->
onEnterCode(et.text.toString())
}
.show()
}
binding.disableButton.setOnClickListener {
AlertDialog.Builder(this)
.setTitle(R.string.disable_sync)
.setMessage(R.string.disable_sync_description)
.setPositiveButton(R.string.disable) { _, _ ->
onDisableSync()
}
.setNegativeButton(R.string.keep_enabled) { dialog, _ ->
dialog.dismiss()
}
.show()
}
setContentView(binding.root)
}
private fun onGenerateCode() {
showCodeScreen()
}
private fun onEnterCode(code: String) {
showCodeScreen()
}
private fun onDisableSync() {
showIntroScreen()
}
private fun showCodeScreen() {
binding.introGroup.visibility = View.GONE
binding.codeGroup.visibility = View.VISIBLE
}
private fun showIntroScreen() {
binding.introGroup.visibility = View.VISIBLE
binding.codeGroup.visibility = View.GONE
}
}

View File

@@ -24,7 +24,6 @@ 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?) {
@@ -33,7 +32,7 @@ class EditSettingActivity : AppCompatActivity() {
val habits = app.component.habitList.getFiltered(
HabitMatcher(
isArchivedAllowed = false,
isCompletedAllowed = true
isCompletedAllowed = true,
)
)
AndroidThemeSwitcher(this, app.component.preferences).apply()
@@ -44,9 +43,8 @@ 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,34 +27,22 @@ 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,6 +25,5 @@ import dagger.Provides
@Module
class ActivityContextModule(
@get:Provides
@get:ActivityContext
val context: Context
@get:ActivityContext val context: Context
)

View File

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

View File

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

View File

@@ -96,6 +96,7 @@ class AndroidNotificationTray
timestamp: Timestamp,
disableSound: Boolean = false
): Notification {
val addRepetitionAction = Action(
R.drawable.ic_action_check,
context.getString(R.string.yes),
@@ -145,9 +146,8 @@ class AndroidNotificationTray
.addAction(removeRepetitionAction)
}
if (!disableSound) {
if (!disableSound)
builder.setSound(ringtoneManager.getURI())
}
if (SDK_INT < Build.VERSION_CODES.S) {
val snoozeAction = Action(

View File

@@ -61,9 +61,8 @@ class RingtoneManager
"pref_ringtone_uri",
defaultRingtoneUri.toString()
)!!
if (prefRingtoneUri.isNotEmpty()) {
if (prefRingtoneUri.isNotEmpty())
ringtoneUri = Uri.parse(prefRingtoneUri)
}
return ringtoneUri
}

View File

@@ -33,8 +33,7 @@ import org.isoron.uhabits.HabitsApplication
import org.isoron.uhabits.R
import org.isoron.uhabits.activities.AndroidThemeSwitcher
import org.isoron.uhabits.core.models.Habit
import org.isoron.uhabits.core.ui.views.DarkTheme
import org.isoron.uhabits.core.ui.views.LightTheme
import org.isoron.uhabits.core.ui.ThemeSwitcher.Companion.THEME_LIGHT
import org.isoron.uhabits.receivers.ReminderController
import org.isoron.uhabits.utils.SystemUtils
import java.util.Calendar
@@ -52,8 +51,11 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener {
val app = applicationContext as HabitsApplication
val appComponent = app.component
val themeSwitcher = AndroidThemeSwitcher(this, appComponent.preferences)
themeSwitcher.setTheme()
if (themeSwitcher.getSystemTheme() == THEME_LIGHT) {
setTheme(R.style.BaseDialog)
} else {
setTheme(R.style.BaseDialogDark)
}
val data = intent.data
if (data == null) {
finish()
@@ -73,16 +75,6 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener {
SystemUtils.unlockScreen(this)
}
private fun AndroidThemeSwitcher.setTheme() {
if (this.isNightMode) {
setTheme(R.style.BaseDialogDark)
this.currentTheme = DarkTheme()
} else {
setTheme(R.style.BaseDialog)
this.currentTheme = LightTheme()
}
}
private fun showTimePicker() {
val calendar = Calendar.getInstance()
val dialog = TimePickerDialog.newInstance(
@@ -103,9 +95,7 @@ class SnoozeDelayPickerActivity : FragmentActivity(), OnItemClickListener {
if (snoozeValues[position] >= 0) {
reminderController!!.onSnoozeDelayPicked(habit!!, snoozeValues[position])
finish()
} else {
showTimePicker()
}
} else showTimePicker()
}
override fun finish() {

View File

@@ -66,13 +66,7 @@ class ReminderController @Inject constructor(
}
fun onDismiss(habit: Habit) {
if (preferences.shouldMakeNotificationsSticky()) {
// This is a workaround to keep sticky notifications non-dismissible in Android 14+.
// If the notification is dismissed, we immediately reshow it.
notificationTray.reshow(habit)
} else {
notificationTray.cancel(habit)
}
notificationTray.cancel(habit)
}
private fun showSnoozeDelayPicker(habit: Habit, context: Context) {

View File

@@ -60,14 +60,12 @@ class AndroidTaskRunner : TaskRunner {
publishProgress(progress)
}
@Deprecated("Deprecated in Java")
override fun doInBackground(vararg params: Void?): Void? {
if (isCancelled) return null
task.doInBackground()
return null
}
@Deprecated("Deprecated in Java")
override fun onPostExecute(aVoid: Void?) {
if (isCancelled) return
task.onPostExecute()
@@ -76,7 +74,6 @@ class AndroidTaskRunner : TaskRunner {
for (l in listeners) l.onTaskFinished(task)
}
@Deprecated("Deprecated in Java")
override fun onPreExecute() {
if (isCancelled) return
for (l in listeners) l.onTaskStarted(task)
@@ -85,7 +82,6 @@ class AndroidTaskRunner : TaskRunner {
task.onPreExecute()
}
@Deprecated("Deprecated in Java")
override fun onProgressUpdate(vararg values: Int?) {
values[0]?.let { task.onProgressUpdate(it) }
}

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