diff --git a/Habitica/build.gradle b/Habitica/build.gradle
index 48b85dc6b..c3d3b0be9 100644
--- a/Habitica/build.gradle
+++ b/Habitica/build.gradle
@@ -194,7 +194,7 @@ android {
dimension "buildType"
}
- beta {
+ alpha {
dimension "buildType"
buildConfigField "String", "TESTING_LEVEL", "\"alpha\""
resValue "string", "app_name", "Habitica Alpha"
diff --git a/Habitica/res/xml/network_security_config.xml b/Habitica/res/xml/network_security_config.xml
index bd229b92f..a11c6d527 100644
--- a/Habitica/res/xml/network_security_config.xml
+++ b/Habitica/res/xml/network_security_config.xml
@@ -5,4 +5,7 @@
+
+ 192.168.178.51
+
\ No newline at end of file
diff --git a/Habitica/res/xml/remote_config_defaults.xml b/Habitica/res/xml/remote_config_defaults.xml
index 8f31e17e2..4158c910c 100644
--- a/Habitica/res/xml/remote_config_defaults.xml
+++ b/Habitica/res/xml/remote_config_defaults.xml
@@ -22,11 +22,15 @@
enableLocalChanges
- true
+ false
+
+
+ enableLocalTaskScoring
+ false
lastVersionNumber
-
+ 1.0
lastVersionCode
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
index 4f9ca97eb..6e98dacd2 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/TaskRepository.kt
@@ -22,8 +22,8 @@ interface TaskRepository : BaseRepository {
fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable
fun retrieveTasks(userId: String, tasksOrder: TasksOrder, dueDate: Date): Flowable
- fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean): Flowable
- fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean): Maybe
+ fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable
+ fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe
fun scoreChecklistItem(taskId: String, itemId: String): Flowable
fun getTask(taskId: String): Flowable
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
index baf897de3..524bcae90 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/TaskRepositoryImpl.kt
@@ -3,25 +3,25 @@ package com.habitrpg.android.habitica.data.implementation
import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.local.TaskLocalRepository
+import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.RxErrorHandler
-import com.habitrpg.android.habitica.models.Tag
+import com.habitrpg.android.habitica.interactors.ScoreTaskLocallyInteractor
import com.habitrpg.android.habitica.models.responses.TaskDirection
+import com.habitrpg.android.habitica.models.responses.TaskDirectionData
import com.habitrpg.android.habitica.models.responses.TaskScoringResult
import com.habitrpg.android.habitica.models.tasks.*
import com.habitrpg.android.habitica.models.user.User
-import com.playseeds.android.sdk.inappmessaging.Log
import io.reactivex.Flowable
import io.reactivex.Maybe
import io.reactivex.Single
import io.reactivex.functions.Consumer
import io.realm.Realm
-import io.realm.RealmList
import io.realm.RealmResults
import java.text.SimpleDateFormat
import java.util.*
-class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiClient, userID: String) : BaseRepositoryImpl(localRepository, apiClient, userID), TaskRepository {
+class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiClient, userID: String, val appConfigManager: AppConfigManager) : BaseRepositoryImpl(localRepository, apiClient, userID), TaskRepository {
override fun getTasksOfType(taskType: String): Flowable> = getTasks(taskType, userID)
private var lastTaskAction: Long = 0
@@ -58,65 +58,91 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli
}
@Suppress("ReturnCount")
- override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean): Flowable {
+ override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable {
+ val localData = if (user != null && appConfigManager.enableLocalTaskScoring()) {
+ ScoreTaskLocallyInteractor.score(user, task, if (up) TaskDirection.UP else TaskDirection.DOWN)
+ } else null
+ if (user != null && localData != null) {
+ val stats = user.stats
+ val result = TaskScoringResult()
+
+ result.healthDelta = localData.hp - (stats?.hp ?: 0.0)
+ result.experienceDelta = localData.exp - (stats?.exp ?: 0.0)
+ result.manaDelta = localData.mp - (stats?.mp ?: 0.0)
+ result.goldDelta = localData.gp - (stats?.gp ?: 0.0)
+ result.hasLeveledUp = localData.lvl > stats?.lvl ?: 0
+ result.questDamage = localData._tmp?.quest?.progressDelta
+ result.drop = localData._tmp?.drop
+ notifyFunc?.invoke(result)
+
+ handleTaskResponse(user, localData, task, up, 0f)
+ }
val now = Date().time
val id = task.id
if (lastTaskAction > now - 500 && !force || id == null) {
return Flowable.empty()
}
lastTaskAction = now
- return this.apiClient.postTaskDirection(id, (if (up) TaskDirection.up else TaskDirection.down).toString())
+ return this.apiClient.postTaskDirection(id, (if (up) TaskDirection.UP else TaskDirection.DOWN).text)
.map { res ->
// save local task changes
val result = TaskScoringResult()
if (user != null) {
val stats = user.stats
- result.taskValueDelta = res.delta
result.healthDelta = res.hp - (stats?.hp ?: 0.0)
result.experienceDelta = res.exp - (stats?.exp ?: 0.0)
result.manaDelta = res.mp - (stats?.mp ?: 0.0)
result.goldDelta = res.gp - (stats?.gp ?: 0.0)
result.hasLeveledUp = res.lvl > stats?.lvl ?: 0
- result.questDamage = res._tmp.quest?.progressDelta
- if (res._tmp != null) {
- result.drop = res._tmp.drop
- }
- this.localRepository.executeTransaction {
- if (!task.isValid) {
- return@executeTransaction
- }
- if (task.type != "reward") {
- task.value = task.value + res.delta
- if (Task.TYPE_DAILY == task.type || Task.TYPE_TODO == task.type) {
- task.completed = up
- if (Task.TYPE_DAILY == task.type && up) {
- task.streak = (task.streak ?: 0) + 1
- }
- } else if (Task.TYPE_HABIT == task.type) {
- if (up) {
- task.counterUp = (task.counterUp ?: 0) + 1
- } else {
- task.counterDown = (task.counterDown ?: 0) + 1
- }
- }
- }
- stats?.hp = res.hp
- stats?.exp = res.exp
- stats?.mp = res.mp
- stats?.gp = res.gp
- stats?.lvl = res.lvl
- user.party?.quest?.progress?.up = (user.party?.quest?.progress?.up ?: 0F) + (res._tmp.quest?.progressDelta?.toFloat() ?: 0F)
- user.stats = stats
+ result.questDamage = res._tmp?.quest?.progressDelta
+ result.drop = res._tmp?.drop
+ if (localData == null) {
+ notifyFunc?.invoke(result)
}
}
+ handleTaskResponse(user, res, task, up, localData?.delta ?: 0f)
result
}
}
- override fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean): Maybe {
+ private fun handleTaskResponse(user: User?, res: TaskDirectionData, task: Task, up: Boolean, localDelta: Float) {
+ if (user != null) {
+ val stats = user.stats
+ this.localRepository.executeTransaction {
+ if (!task.isValid) {
+ return@executeTransaction
+ }
+ if (task.type != "reward" && (task.value - localDelta) + res.delta != task.value) {
+ task.value = (task.value - localDelta) + res.delta
+ if (Task.TYPE_DAILY == task.type || Task.TYPE_TODO == task.type) {
+ task.completed = up
+ if (Task.TYPE_DAILY == task.type && up) {
+ task.streak = (task.streak ?: 0) + 1
+ }
+ } else if (Task.TYPE_HABIT == task.type) {
+ if (up) {
+ task.counterUp = (task.counterUp ?: 0) + 1
+ } else {
+ task.counterDown = (task.counterDown ?: 0) + 1
+ }
+ }
+ }
+ stats?.hp = res.hp
+ stats?.exp = res.exp
+ stats?.mp = res.mp
+ stats?.gp = res.gp
+ stats?.lvl = res.lvl
+ user.party?.quest?.progress?.up = (user.party?.quest?.progress?.up
+ ?: 0F) + (res._tmp?.quest?.progressDelta?.toFloat() ?: 0F)
+ user.stats = stats
+ }
+ }
+ }
+
+ override fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe {
return localRepository.getTask(taskId).firstElement()
- .flatMap { task -> taskChecked(user, task, up, force).singleElement() }
+ .flatMap { task -> taskChecked(user, task, up, force, notifyFunc).singleElement() }
}
override fun scoreChecklistItem(taskId: String, itemId: String): Flowable {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt
index 5955f4621..28d78a842 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.kt
@@ -267,7 +267,7 @@ class UserRepositoryImpl(localRepository: UserLocalRepository, apiClient: ApiCli
}
if (tasks.isNotEmpty()) {
for (task in tasks) {
- observable = observable.flatMap { taskRepository.taskChecked(null, task, true, true).firstElement() }
+ observable = observable.flatMap { taskRepository.taskChecked(null, task, true, true, null).firstElement() }
}
}
observable.flatMap { apiClient.runCron().firstElement() }
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
index 23a6bb02f..5935f9fd4 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/helpers/AppConfigManager.kt
@@ -61,4 +61,8 @@ class AppConfigManager {
fun testingLevel(): AppTestingLevel {
return AppTestingLevel.valueOf(BuildConfig.TESTING_LEVEL)
}
+
+ fun enableLocalTaskScoring(): Boolean {
+ return remoteConfig.getBoolean("enableLocalTaskScoring")
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.java
deleted file mode 100644
index d93694f0c..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package com.habitrpg.android.habitica.interactors;
-
-import com.habitrpg.android.habitica.data.TaskRepository;
-import com.habitrpg.android.habitica.executors.PostExecutionThread;
-import com.habitrpg.android.habitica.executors.ThreadExecutor;
-import com.habitrpg.android.habitica.helpers.SoundManager;
-import com.habitrpg.android.habitica.models.responses.TaskScoringResult;
-import com.habitrpg.android.habitica.models.tasks.Task;
-import com.habitrpg.android.habitica.models.user.User;
-
-import javax.inject.Inject;
-
-import io.reactivex.Flowable;
-
-public class BuyRewardUseCase extends UseCase {
-
- private TaskRepository taskRepository;
- private SoundManager soundManager;
-
- @Inject
- public BuyRewardUseCase(TaskRepository taskRepository, SoundManager soundManager,
- ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
- super(threadExecutor, postExecutionThread);
- this.taskRepository = taskRepository;
- this.soundManager = soundManager;
- }
-
- @Override
- protected Flowable buildUseCaseObservable(BuyRewardUseCase.RequestValues requestValues) {
- return taskRepository
- .taskChecked(requestValues.user, requestValues.task, false, false)
- .doOnNext(res -> soundManager.loadAndPlayAudio(SoundManager.SoundReward));
- }
-
- public static final class RequestValues implements UseCase.RequestValues {
- protected final Task task;
- private final User user;
-
- public RequestValues(User user, Task task) {
- this.user = user;
- this.task = task;
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.kt
new file mode 100644
index 000000000..a3c028968
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/BuyRewardUseCase.kt
@@ -0,0 +1,26 @@
+package com.habitrpg.android.habitica.interactors
+
+import com.habitrpg.android.habitica.data.TaskRepository
+import com.habitrpg.android.habitica.executors.PostExecutionThread
+import com.habitrpg.android.habitica.executors.ThreadExecutor
+import com.habitrpg.android.habitica.helpers.SoundManager
+import com.habitrpg.android.habitica.models.responses.TaskScoringResult
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.User
+
+import javax.inject.Inject
+
+import io.reactivex.Flowable
+
+class BuyRewardUseCase @Inject
+constructor(private val taskRepository: TaskRepository, private val soundManager: SoundManager,
+ threadExecutor: ThreadExecutor, postExecutionThread: PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
+
+ override fun buildUseCaseObservable(requestValues: BuyRewardUseCase.RequestValues): Flowable {
+ return taskRepository
+ .taskChecked(requestValues.user, requestValues.task, false, false, requestValues.notifyFunc)
+ .doOnNext { soundManager.loadAndPlayAudio(SoundManager.SoundReward) }
+ }
+
+ class RequestValues(internal val user: User?, val task: Task, val notifyFunc: (TaskScoringResult) -> Unit) : UseCase.RequestValues
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java
deleted file mode 100644
index 61bfaf679..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.habitrpg.android.habitica.interactors;
-
-import com.habitrpg.android.habitica.data.TaskRepository;
-import com.habitrpg.android.habitica.executors.PostExecutionThread;
-import com.habitrpg.android.habitica.executors.ThreadExecutor;
-import com.habitrpg.android.habitica.helpers.SoundManager;
-import com.habitrpg.android.habitica.models.responses.TaskScoringResult;
-import com.habitrpg.android.habitica.models.tasks.Task;
-import com.habitrpg.android.habitica.models.user.User;
-
-import javax.inject.Inject;
-
-import io.reactivex.Flowable;
-
-public class DailyCheckUseCase extends UseCase {
-
- private TaskRepository taskRepository;
- private SoundManager soundManager;
-
- @Inject
- public DailyCheckUseCase(TaskRepository taskRepository, SoundManager soundManager,
- ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
- super(threadExecutor, postExecutionThread);
- this.taskRepository = taskRepository;
- this.soundManager = soundManager;
- }
-
- @Override
- protected Flowable buildUseCaseObservable(RequestValues requestValues) {
- return taskRepository.taskChecked(requestValues.user, requestValues.task, requestValues.up, false).doOnNext(res -> soundManager.loadAndPlayAudio(SoundManager.SoundDaily));
- }
-
- public static final class RequestValues implements UseCase.RequestValues {
-
- protected boolean up = false;
-
- protected final Task task;
- public User user;
-
- public RequestValues(User user, Task task, boolean up) {
- this.user = user;
- this.task = task;
- this.up = up;
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.kt
new file mode 100644
index 000000000..629d2e214
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/DailyCheckUseCase.kt
@@ -0,0 +1,32 @@
+package com.habitrpg.android.habitica.interactors
+
+import com.habitrpg.android.habitica.data.TaskRepository
+import com.habitrpg.android.habitica.executors.PostExecutionThread
+import com.habitrpg.android.habitica.executors.ThreadExecutor
+import com.habitrpg.android.habitica.helpers.SoundManager
+import com.habitrpg.android.habitica.models.responses.TaskScoringResult
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.User
+
+import javax.inject.Inject
+
+import io.reactivex.Flowable
+
+class DailyCheckUseCase @Inject
+constructor(private val taskRepository: TaskRepository, private val soundManager: SoundManager,
+ threadExecutor: ThreadExecutor, postExecutionThread: PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
+
+ override fun buildUseCaseObservable(requestValues: RequestValues): Flowable {
+ return taskRepository.taskChecked(requestValues.user, requestValues.task, requestValues.up, false, requestValues.notifyFunc)
+ .doOnNext { soundManager.loadAndPlayAudio(SoundManager.SoundDaily) }
+ }
+
+ class RequestValues(var user: User?, val task: Task, up: Boolean, val notifyFunc: (TaskScoringResult) -> Unit) : UseCase.RequestValues {
+
+ var up = false
+
+ init {
+ this.up = up
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.java
deleted file mode 100644
index 62ee3b3c8..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.habitrpg.android.habitica.interactors;
-
-import com.habitrpg.android.habitica.data.TaskRepository;
-import com.habitrpg.android.habitica.executors.PostExecutionThread;
-import com.habitrpg.android.habitica.executors.ThreadExecutor;
-import com.habitrpg.android.habitica.helpers.SoundManager;
-import com.habitrpg.android.habitica.models.responses.TaskScoringResult;
-import com.habitrpg.android.habitica.models.tasks.Task;
-import com.habitrpg.android.habitica.models.user.User;
-
-import javax.inject.Inject;
-
-import io.reactivex.Flowable;
-
-public class HabitScoreUseCase extends UseCase {
-
- private TaskRepository taskRepository;
- private SoundManager soundManager;
-
- @Inject
- public HabitScoreUseCase(TaskRepository taskRepository, SoundManager soundManager,
- ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
- super(threadExecutor, postExecutionThread);
- this.taskRepository = taskRepository;
- this.soundManager = soundManager;
- }
-
- @Override
- protected Flowable buildUseCaseObservable(RequestValues requestValues) {
- return taskRepository
- .taskChecked(requestValues.user, requestValues.habit, requestValues.up, false)
- .doOnNext(res -> soundManager.loadAndPlayAudio(requestValues.up ? SoundManager.SoundPlusHabit : SoundManager.SoundMinusHabit));
- }
-
- public static final class RequestValues implements UseCase.RequestValues {
-
- private final User user;
- protected boolean up = false;
-
- protected final Task habit;
-
- public RequestValues(User user, Task habit, boolean up) {
- this.user = user;
- this.habit = habit;
- this.up = up;
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.kt
new file mode 100644
index 000000000..4dfbc5792
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/HabitScoreUseCase.kt
@@ -0,0 +1,32 @@
+package com.habitrpg.android.habitica.interactors
+
+import com.habitrpg.android.habitica.data.TaskRepository
+import com.habitrpg.android.habitica.executors.PostExecutionThread
+import com.habitrpg.android.habitica.executors.ThreadExecutor
+import com.habitrpg.android.habitica.helpers.SoundManager
+import com.habitrpg.android.habitica.models.responses.TaskScoringResult
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.User
+
+import javax.inject.Inject
+
+import io.reactivex.Flowable
+
+class HabitScoreUseCase @Inject
+constructor(private val taskRepository: TaskRepository, private val soundManager: SoundManager,
+ threadExecutor: ThreadExecutor, postExecutionThread: PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
+
+ override fun buildUseCaseObservable(requestValues: RequestValues): Flowable {
+ return taskRepository
+ .taskChecked(requestValues.user, requestValues.habit, requestValues.up, false, requestValues.notifyFunc)
+ .doOnNext { soundManager.loadAndPlayAudio(if (requestValues.up) SoundManager.SoundPlusHabit else SoundManager.SoundMinusHabit) }
+ }
+
+ class RequestValues(internal val user: User?, val habit: Task, up: Boolean, val notifyFunc: (TaskScoringResult) -> Unit) : UseCase.RequestValues {
+ var up = false
+
+ init {
+ this.up = up
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt
index cd0b3400a..e70592dd9 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/LevelUpUseCase.kt
@@ -47,7 +47,7 @@ constructor(private val soundManager: SoundManager, threadExecutor: ThreadExecut
}
val event = ShareEvent()
- event.sharedMessage = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel) + " https://habitica.com/social/level-up"
+ event.sharedMessage = requestValues.activity.getString(R.string.share_levelup, requestValues.newLevel) + " https://habitica.com/social/level-UP"
val avatarView = AvatarView(requestValues.activity, true, true, true)
avatarView.setAvatar(requestValues.user)
avatarView.onAvatarImageReady(object : AvatarView.Consumer {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt
new file mode 100644
index 000000000..c4d2d2d4f
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/ScoreTaskLocallyInteractor.kt
@@ -0,0 +1,156 @@
+package com.habitrpg.android.habitica.interactors
+
+import com.habitrpg.android.habitica.extensions.notNull
+import com.habitrpg.android.habitica.models.responses.TaskDirection
+import com.habitrpg.android.habitica.models.responses.TaskDirectionData
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.Stats
+import com.habitrpg.android.habitica.models.user.User
+import java.util.ArrayList
+
+class ScoreTaskLocallyInteractor {
+ companion object {
+ const val MAX_TASK_VALUE = 21.27
+ const val MIN_TASK_VALUE = -47.27
+ const val CLOSE_ENOUGH = 0.00001
+
+ private fun calculateDelta(task: Task, direction: TaskDirection): Double {
+ val currentValue = when {
+ task.value < MIN_TASK_VALUE -> MIN_TASK_VALUE
+ task.value > MAX_TASK_VALUE -> MAX_TASK_VALUE
+ else -> task.value
+ }
+
+ var nextDelta = Math.pow(0.9747, currentValue) * if (direction == TaskDirection.DOWN) -1 else 1
+
+ if (task.checklist?.size ?: 0 > 0) {
+ if (task.type == Task.TYPE_TODO) {
+ nextDelta *= 1 + (task.checklist?.map { if (it.completed) 1 else 0 }?.reduce { acc, i -> 0 }
+ ?: 0)
+ }
+ }
+
+ return nextDelta
+ }
+
+ private fun scoreHabit(user: User, task: Task, direction: TaskDirection) {
+
+ }
+
+ private fun scoreDaily(user: User, task: Task, direction: TaskDirection) {
+
+ }
+
+ private fun scoreToDo(user: User, task: Task, direction: TaskDirection) {
+
+ }
+
+ fun score(user: User, task: Task, direction: TaskDirection): TaskDirectionData? {
+ return if (task.type == Task.TYPE_HABIT || direction == TaskDirection.UP) {
+ val stats = user.stats ?: return null
+ val computedStats = computeStats(user)
+ val result = TaskDirectionData()
+ result.hp = stats.hp ?: 0.0
+ result.exp = stats.exp ?: 0.0
+ result.gp = stats.gp ?: 0.0
+ result.mp = stats.mp ?: 0.0
+ val delta = calculateDelta(task, direction)
+ result.delta = delta.toFloat()
+ if (delta > 0) {
+ addPoints(result, delta, stats, computedStats, task, direction)
+ } else {
+ subtractPoints(result, delta, stats, computedStats, task)
+ }
+
+ when (task.type) {
+ Task.TYPE_HABIT -> scoreHabit(user, task, direction)
+ Task.TYPE_DAILY -> scoreDaily(user, task, direction)
+ Task.TYPE_TODO -> scoreToDo(user, task, direction)
+ }
+
+ if (result.hp <= 0.0) {
+ result.hp = 0.0
+ }
+ if (result.exp >= stats.toNextLevel?.toDouble() ?: 0.0) {
+ result.exp = result.exp - (stats.toNextLevel?.toDouble() ?: 0.0)
+ result.lvl = user.stats?.lvl ?: 0 + 1
+ result.hp = 50.0
+ } else {
+ result.lvl = user.stats?.lvl ?: 0
+ }
+
+ result
+ } else {
+ null
+ }
+ }
+
+ private fun subtractPoints(result: TaskDirectionData, delta: Double, stats: Stats, computedStats: Stats, task: Task) {
+ var conBonus = 1f - ((computedStats.con?.toFloat() ?: 0f) / 250f)
+ if (conBonus < 0.1) {
+ conBonus = 0.1f
+ }
+ val hpMod = delta * conBonus * task.priority * 2
+ result.hp = (stats.hp ?: 0.0) + Math.round(hpMod * 10) / 10.0
+ }
+
+ private fun addPoints(result: TaskDirectionData, delta: Double, stats: Stats, computedStats: Stats, task: Task, direction: TaskDirection) {
+ val intBonus = 1f + ((computedStats._int?.toFloat() ?: 0f) * 0.025f)
+ result.exp = (stats.exp
+ ?: 0.0) + Math.round(delta * intBonus * task.priority * 6).toDouble()
+
+ val perBonus = 1f + ((computedStats.per?.toFloat() ?: 0f) * 0.02f)
+ val goldMod = delta * task.priority * perBonus
+
+ val streak = task.streak ?: 0
+ result.gp = (stats.gp ?: 0.0) + if (task.streak != null) {
+ val currentStreak = if (direction == TaskDirection.DOWN) streak - 1 else streak
+ val streakBonus = (currentStreak / 100) * 1
+ val afterStreak = goldMod * streakBonus
+ afterStreak
+ } else {
+ goldMod
+ }
+ }
+
+ private fun computeStats(user: User): Stats {
+ val levelStat = Math.min((user.stats?.lvl ?: 0) / 2.0f, 50f).toInt()
+
+ var totalStrength = levelStat
+ var totalIntelligence = levelStat
+ var totalConstitution = levelStat
+ var totalPerception = levelStat
+
+ totalStrength += user.stats?.buffs?.getStr()?.toInt() ?: 0
+ totalIntelligence += user.stats?.buffs?.get_int()?.toInt() ?: 0
+ totalConstitution += user.stats?.buffs?.getCon()?.toInt() ?: 0
+ totalPerception += user.stats?.buffs?.getPer()?.toInt() ?: 0
+
+ totalStrength += user.stats?.str ?: 0
+ totalIntelligence += user.stats?._int ?: 0
+ totalConstitution += user.stats?.con ?: 0
+ totalPerception += user.stats?.per ?: 0
+
+ val outfit = user.items?.gear?.equipped
+ val outfitList = ArrayList()
+ outfit.notNull { thisOutfit ->
+ outfitList.add(thisOutfit.armor)
+ outfitList.add(thisOutfit.back)
+ outfitList.add(thisOutfit.body)
+ outfitList.add(thisOutfit.eyeWear)
+ outfitList.add(thisOutfit.head)
+ outfitList.add(thisOutfit.headAccessory)
+ outfitList.add(thisOutfit.shield)
+ outfitList.add(thisOutfit.weapon)
+ }
+
+ val stats = Stats()
+ stats.str = totalStrength
+ stats._int = totalIntelligence
+ stats.con = totalConstitution
+ stats.per = totalPerception
+
+ return stats
+ }
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.java b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.java
deleted file mode 100644
index 1cd56aee3..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.habitrpg.android.habitica.interactors;
-
-import com.habitrpg.android.habitica.data.TaskRepository;
-import com.habitrpg.android.habitica.executors.PostExecutionThread;
-import com.habitrpg.android.habitica.executors.ThreadExecutor;
-import com.habitrpg.android.habitica.helpers.SoundManager;
-import com.habitrpg.android.habitica.models.responses.TaskScoringResult;
-import com.habitrpg.android.habitica.models.tasks.Task;
-import com.habitrpg.android.habitica.models.user.User;
-
-import javax.inject.Inject;
-
-import io.reactivex.Flowable;
-
-public class TodoCheckUseCase extends UseCase {
-
- private TaskRepository taskRepository;
- private SoundManager soundManager;
-
- @Inject
- public TodoCheckUseCase(TaskRepository taskRepository, SoundManager soundManager,
- ThreadExecutor threadExecutor, PostExecutionThread postExecutionThread) {
- super(threadExecutor, postExecutionThread);
- this.taskRepository = taskRepository;
- this.soundManager = soundManager;
- }
-
- @Override
- protected Flowable buildUseCaseObservable(TodoCheckUseCase.RequestValues requestValues) {
- return taskRepository.taskChecked(requestValues.user, requestValues.task, requestValues.up, false).doOnNext(res -> soundManager.loadAndPlayAudio(SoundManager.SoundTodo));
- }
-
- public static final class RequestValues implements UseCase.RequestValues {
-
- protected boolean up = false;
-
- protected final Task task;
- public User user;
-
- public RequestValues(User user, Task task, boolean up) {
- this.user = user;
- this.task = task;
- this.up = up;
- }
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.kt
new file mode 100644
index 000000000..1e3685e8b
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/interactors/TodoCheckUseCase.kt
@@ -0,0 +1,31 @@
+package com.habitrpg.android.habitica.interactors
+
+import com.habitrpg.android.habitica.data.TaskRepository
+import com.habitrpg.android.habitica.executors.PostExecutionThread
+import com.habitrpg.android.habitica.executors.ThreadExecutor
+import com.habitrpg.android.habitica.helpers.SoundManager
+import com.habitrpg.android.habitica.models.responses.TaskScoringResult
+import com.habitrpg.android.habitica.models.tasks.Task
+import com.habitrpg.android.habitica.models.user.User
+
+import javax.inject.Inject
+
+import io.reactivex.Flowable
+
+class TodoCheckUseCase @Inject
+constructor(private val taskRepository: TaskRepository, private val soundManager: SoundManager,
+ threadExecutor: ThreadExecutor, postExecutionThread: PostExecutionThread) : UseCase(threadExecutor, postExecutionThread) {
+
+ override fun buildUseCaseObservable(requestValues: TodoCheckUseCase.RequestValues): Flowable {
+ return taskRepository.taskChecked(requestValues.user, requestValues.task, requestValues.up, false, requestValues.notifyFunc).doOnNext { soundManager.loadAndPlayAudio(SoundManager.SoundTodo) }
+ }
+
+ class RequestValues(var user: User?, val task: Task, up: Boolean, val notifyFunc: (TaskScoringResult) -> Unit) : UseCase.RequestValues {
+
+ var up = false
+
+ init {
+ this.up = up
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.java
deleted file mode 100644
index 3ff70a5da..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.habitrpg.android.habitica.models.responses;
-
-/**
- * Created by MagicMicky on 16/03/14.
- */
-public enum TaskDirection {
- up("up"),
- down("down");
- private final String dir;
-
- TaskDirection(String dir) {
- this.dir = dir;
- }
-
- public String toString() {
- return this.dir;
- }
-
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.kt
new file mode 100644
index 000000000..80c1713ad
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirection.kt
@@ -0,0 +1,6 @@
+package com.habitrpg.android.habitica.models.responses
+
+enum class TaskDirection(val text: String) {
+ UP("up"),
+ DOWN("down");
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.java b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.java
deleted file mode 100644
index dd571d73a..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.habitrpg.android.habitica.models.responses;
-
-/**
- * This class represent the data sent back from the API when calling /user/tasks/{id}/{direction}.
- * It holds almost the same thing as Stats, except toNextLevel & maxHealth & maxHP.
- * It also holds a delta, which represent the task value modification.
- * Created by MagicMicky on 12/06/2014.
- */
-public class TaskDirectionData {
- private float delta;
- private TaskDirectionDataTemp _tmp;
- public Double exp;
- public Double hp;
- public Double gp;
- public Double mp;
- public Integer lvl;
-
- public float getDelta() {
- return delta;
- }
-
- public void setDelta(float delta) {
- this.delta = delta;
- }
-
- public TaskDirectionDataTemp get_tmp() {
- return _tmp;
- }
-
- public void set_tmp(TaskDirectionDataTemp tmp) {
- this._tmp = tmp;
- }
-
- public Double getExp() {
- return exp;
- }
-
- public Double getHp() {
- return hp;
- }
-
- public Double getGp() {
- return gp;
- }
-
- public Double getMp() {
- return mp;
- }
-
- public Integer getLvl() {
- return lvl;
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.kt
new file mode 100644
index 000000000..4cd586f44
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionData.kt
@@ -0,0 +1,17 @@
+package com.habitrpg.android.habitica.models.responses
+
+/**
+ * This class represent the data sent back from the API when calling /user/tasks/{id}/{direction}.
+ * It holds almost the same thing as Stats, except toNextLevel & maxHealth & maxHP.
+ * It also holds a delta, which represent the task value modification.
+ * Created by MagicMicky on 12/06/2014.
+ */
+class TaskDirectionData {
+ var delta: Float = 0.toFloat()
+ var _tmp: TaskDirectionDataTemp? = null
+ var exp: Double = 0.0
+ var hp: Double = 0.0
+ var gp: Double = 0.0
+ var mp: Double = 0.0
+ var lvl: Int = 0
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionDataTemp.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionDataTemp.kt
index 38f35b8ba..42f4e3e7c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionDataTemp.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskDirectionDataTemp.kt
@@ -4,7 +4,7 @@ class TaskDirectionDataTemp {
var drop: TaskDirectionDataDrop? = null
var quest: TaskDirectionDataQuest? = null
-
+ var crit: Float? = null
}
class TaskDirectionDataQuest {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskScoringResult.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskScoringResult.kt
index 2c6147632..bd20eb9b1 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskScoringResult.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/responses/TaskScoringResult.kt
@@ -2,7 +2,6 @@ package com.habitrpg.android.habitica.models.responses
class TaskScoringResult {
- var taskValueDelta: Float? = null
var drop: TaskDirectionDataDrop? = null
var experienceDelta: Double? = null
var healthDelta: Double? = null
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/RepositoryModule.java b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/RepositoryModule.java
index 384ad0f5a..122c2933d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/modules/RepositoryModule.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/modules/RepositoryModule.java
@@ -71,8 +71,8 @@ public class RepositoryModule {
@Provides
@Singleton
- TaskRepository providesTaskRepository(TaskLocalRepository localRepository, ApiClient apiClient, @Named(AppModule.NAMED_USER_ID) String userId) {
- return new TaskRepositoryImpl(localRepository, apiClient, userId);
+ TaskRepository providesTaskRepository(TaskLocalRepository localRepository, ApiClient apiClient, @Named(AppModule.NAMED_USER_ID) String userId, AppConfigManager appConfigManager) {
+ return new TaskRepositoryImpl(localRepository, apiClient, userId, appConfigManager);
}
@Provides
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.kt
index 8344fc4c8..b36dd99bf 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/receivers/TaskReceiver.kt
@@ -39,7 +39,7 @@ class TaskReceiver : BroadcastReceiver() {
if (extras != null) {
val taskTitle = extras.getString(TaskAlarmManager.TASK_NAME_INTENT_KEY)
val taskId = extras.getString(TaskAlarmManager.TASK_ID_INTENT_KEY)
- //This will set up the next reminders for dailies
+ //This will set UP the next reminders for dailies
if (taskId != null) {
taskAlarmManager.addAlarmForTaskId(taskId)
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
index ab45f9374..b80dcd67f 100755
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/MainActivity.kt
@@ -32,7 +32,6 @@ import com.facebook.drawee.view.SimpleDraweeView
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.perf.FirebasePerformance
import com.habitrpg.android.habitica.HabiticaBaseApplication
-import com.habitrpg.android.habitica.MainNavDirections
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.api.HostConfig
import com.habitrpg.android.habitica.api.MaintenanceApiService
@@ -484,14 +483,13 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
HabiticaSnackbar.showSnackbar(floatingMenuWrapper, null, snackbarMessage, BitmapDrawable(resources, HabiticaIconsHelper.imageOfGold()), ContextCompat.getColor(this, R.color.yellow_10), "-" + event.Reward.value, SnackbarDisplayType.NORMAL)
}, RxErrorHandler.handleEmptyError())
} else {
- buyRewardUseCase.observable(BuyRewardUseCase.RequestValues(user, event.Reward))
- .subscribe(Consumer {
- HabiticaSnackbar.showSnackbar(floatingMenuWrapper, null, getString(R.string.notification_purchase_reward),
- BitmapDrawable(resources, HabiticaIconsHelper.imageOfGold()),
- ContextCompat.getColor(this, R.color.yellow_10),
- "-" + event.Reward.value.toInt(),
- SnackbarDisplayType.DROP)
- }, RxErrorHandler.handleEmptyError())
+ buyRewardUseCase.observable(BuyRewardUseCase.RequestValues(user, event.Reward) {
+ HabiticaSnackbar.showSnackbar(floatingMenuWrapper, null, getString(R.string.notification_purchase_reward),
+ BitmapDrawable(resources, HabiticaIconsHelper.imageOfGold()),
+ ContextCompat.getColor(this, R.color.yellow_10),
+ "-" + event.Reward.value.toInt(),
+ SnackbarDisplayType.DROP)
+ }).subscribe(Consumer {}, RxErrorHandler.handleEmptyError())
}
}
@@ -732,12 +730,12 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
fun onEvent(event: TaskCheckedCommand) {
when (event.Task.type) {
Task.TYPE_DAILY -> {
- dailyCheckUseCase.observable(DailyCheckUseCase.RequestValues(user, event.Task, !event.Task.completed))
- .subscribe(Consumer { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
+ dailyCheckUseCase.observable(DailyCheckUseCase.RequestValues(user, event.Task, !event.Task.completed) { result -> displayTaskScoringResponse(result)})
+ .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
}
Task.TYPE_TODO -> {
- todoCheckUseCase.observable(TodoCheckUseCase.RequestValues(user, event.Task, !event.Task.completed))
- .subscribe(Consumer { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
+ todoCheckUseCase.observable(TodoCheckUseCase.RequestValues(user, event.Task, !event.Task.completed) { result -> displayTaskScoringResponse(result)})
+ .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
}
}
}
@@ -749,8 +747,8 @@ open class MainActivity : BaseActivity(), TutorialView.OnTutorialReaction {
@Subscribe
fun onEvent(event: HabitScoreEvent) {
- habitScoreUseCase.observable(HabitScoreUseCase.RequestValues(user, event.habit, event.Up))
- .subscribe(Consumer { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
+ habitScoreUseCase.observable(HabitScoreUseCase.RequestValues(user, event.habit, event.Up) { result -> displayTaskScoringResponse(result)})
+ .subscribe(Consumer { }, RxErrorHandler.handleEmptyError())
}
private fun checkMaintenance() {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AboutFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AboutFragment.kt
index c78ca4dbc..f8893943f 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AboutFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/AboutFragment.kt
@@ -18,6 +18,7 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.AppComponent
import com.habitrpg.android.habitica.extensions.notNull
import com.habitrpg.android.habitica.helpers.AppConfigManager
+import com.habitrpg.android.habitica.helpers.AppTestingLevel
import com.habitrpg.android.habitica.modules.AppModule
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
@@ -129,10 +130,14 @@ class AboutFragment : BaseMainFragment() {
private fun sendEmail(subject: String) {
val version = Build.VERSION.SDK_INT
val device = Build.DEVICE
- var bodyOfEmail = "Device: " + device +
- " \nAndroid Version: " + version +
- " \nAppVersion: " + getString(R.string.version_info, versionName, versionCode) +
- " \nUser ID: " + userId
+ var bodyOfEmail = "Device: $device" +
+ " \nAndroid Version: $version"+
+ " \nAppVersion: " + getString(R.string.version_info, versionName, versionCode)
+
+ if (appConfigManager.testingLevel() != AppTestingLevel.PRODUCTION) {
+ bodyOfEmail += " ${appConfigManager.testingLevel().name}"
+ }
+ bodyOfEmail += " \nUser ID: $userId"
val user = this.user
if (user != null) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt
index 2e623e401..eee9ec0e9 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/NavigationDrawerFragment.kt
@@ -245,7 +245,7 @@ class NavigationDrawerFragment : DialogFragment() {
}
/**
- * Users of this fragment must call this method to set up the navigation drawer interactions.
+ * Users of this fragment must call this method to set UP the navigation drawer interactions.
*
* @param fragmentId The android:id of this fragment in its activity's layout.
* @param drawerLayout The DrawerLayout containing this fragment's UI.
@@ -256,7 +256,7 @@ class NavigationDrawerFragment : DialogFragment() {
// set a custom shadow that overlays the main content when the drawer opens
this.drawerLayout?.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START)
- // set up the drawer's list view with items and click listener
+ // set UP the drawer's list view with items and click listener
}
fun openDrawer() {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetProvider.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetProvider.java
index a4c5b527d..075762649 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetProvider.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetProvider.java
@@ -82,7 +82,7 @@ public class HabitButtonWidgetProvider extends BaseWidgetProvider {
int[] ids = {appWidgetId};
if (taskId != null) {
- getUserRepository().getUser(userId).firstElement().flatMap(user -> taskRepository.taskChecked(user, taskId, TaskDirection.up.toString().equals(direction), false))
+ getUserRepository().getUser(userId).firstElement().flatMap(user -> taskRepository.taskChecked(user, taskId, TaskDirection.UP.toString().equals(direction), false, null))
.subscribe(taskDirectionData -> showToastForTaskDirection(context, taskDirectionData, userId), RxErrorHandler.handleEmptyError(), () -> this.onUpdate(context, mgr, ids));
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java
index 9ce2f39cb..5a34a7aed 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/HabitButtonWidgetService.java
@@ -83,7 +83,7 @@ public class HabitButtonWidgetService extends Service {
} else {
remoteViews.setViewVisibility(R.id.btnPlusWrapper, View.VISIBLE);
remoteViews.setInt(R.id.btnPlus, "setBackgroundColor", ContextCompat.getColor(context, task.getLightTaskColor()));
- remoteViews.setOnClickPendingIntent(R.id.btnPlusWrapper, getPendingIntent(task.getId(), TaskDirection.up.toString(), taskMapping.get(task.getId())));
+ remoteViews.setOnClickPendingIntent(R.id.btnPlusWrapper, getPendingIntent(task.getId(), TaskDirection.UP.getText(), taskMapping.get(task.getId())));
}
if (!task.getDown()) {
remoteViews.setViewVisibility(R.id.btnMinusWrapper, View.GONE);
@@ -91,7 +91,7 @@ public class HabitButtonWidgetService extends Service {
} else {
remoteViews.setViewVisibility(R.id.btnMinusWrapper, View.VISIBLE);
remoteViews.setInt(R.id.btnMinus, "setBackgroundColor", ContextCompat.getColor(context, task.getMediumTaskColor()));
- remoteViews.setOnClickPendingIntent(R.id.btnMinusWrapper, getPendingIntent(task.getId(), TaskDirection.down.toString(), taskMapping.get(task.getId())));
+ remoteViews.setOnClickPendingIntent(R.id.btnMinusWrapper, getPendingIntent(task.getId(), TaskDirection.DOWN.getText(), taskMapping.get(task.getId())));
}
if (taskMapping.get(task.getId()) != null && remoteViews != null) {
appWidgetManager.updateAppWidget(taskMapping.get(task.getId()), remoteViews);
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListWidgetProvider.java b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListWidgetProvider.java
index ca16f1f46..25da6c5dc 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListWidgetProvider.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/widget/TaskListWidgetProvider.java
@@ -57,7 +57,7 @@ public abstract class TaskListWidgetProvider extends BaseWidgetProvider {
String taskId = intent.getStringExtra(TASK_ID_ITEM);
if (taskId != null) {
- getUserRepository().getUser(userId).firstElement().flatMap(user -> taskRepository.taskChecked(user, taskId, true, false))
+ getUserRepository().getUser(userId).firstElement().flatMap(user -> taskRepository.taskChecked(user, taskId, true, false, null))
.subscribe(taskDirectionData -> {
taskRepository.markTaskCompleted(taskId, true);
showToastForTaskDirection(context, taskDirectionData, userId);
diff --git a/Habitica/src/test/java/com/habitrpg/android/habitica/api/TaskAPITests.java b/Habitica/src/test/java/com/habitrpg/android/habitica/api/TaskAPITests.java
index 1571d9fa3..743213277 100644
--- a/Habitica/src/test/java/com/habitrpg/android/habitica/api/TaskAPITests.java
+++ b/Habitica/src/test/java/com/habitrpg/android/habitica/api/TaskAPITests.java
@@ -91,7 +91,7 @@
// @Test
// public void shouldBeAbleToScoreTaskUp() {
// TestSubscriber testSubscriber = new TestSubscriber<>();
-// apiClient.postTaskDirection(habit1.getId(), "up")
+// apiClient.postTaskDirection(habit1.getId(), "UP")
// .subscribe(testSubscriber);
// testSubscriber.awaitTerminalEvent();
// testSubscriber.assertNoErrors();
@@ -103,7 +103,7 @@
// @Test
// public void shouldBeAbleToScoreTaskDown() {
// TestSubscriber testSubscriber = new TestSubscriber<>();
-// apiClient.postTaskDirection(habit1.getId(), "down")
+// apiClient.postTaskDirection(habit1.getId(), "DOWN")
// .subscribe(testSubscriber);
// testSubscriber.awaitTerminalEvent();
// testSubscriber.assertNoErrors();
diff --git a/fastlane/changelog.txt b/fastlane/changelog.txt
index 52503f8b1..2aa00af84 100644
--- a/fastlane/changelog.txt
+++ b/fastlane/changelog.txt
@@ -1,6 +1,3 @@
-- Redesigned Class selection
-- Redesigned Task Form
-- Redesigned Report message dialog
-- Optimized user and content loading
-- Improved FAQ and settings
-- Fixed Time Travelers shop display
+In this update, we've made improvements in many areas of the app and smashed some bugs. Highlights include changes to Settings including easier language selection, fixes for the class selection screen, improvements to the Time Travelers’ Shop, and fixes for Challenge loading, To-Do reminders, and the Record Yesterday’s Activity modal. We’ve also made it easier to find the Habitica Help Guild and the Party Wanted Guild.
+
+Be sure to download this update now for a better Habitica experience!