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!