mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-14 19:56:32 +00:00
Begin implementing local task scoring
This commit is contained in:
parent
7a12357eba
commit
2bb002cbae
33 changed files with 420 additions and 340 deletions
|
|
@ -194,7 +194,7 @@ android {
|
|||
dimension "buildType"
|
||||
}
|
||||
|
||||
beta {
|
||||
alpha {
|
||||
dimension "buildType"
|
||||
buildConfigField "String", "TESTING_LEVEL", "\"alpha\""
|
||||
resValue "string", "app_name", "Habitica Alpha"
|
||||
|
|
|
|||
|
|
@ -5,4 +5,7 @@
|
|||
<certificates src="user" />
|
||||
</trust-anchors>
|
||||
</debug-overrides>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">192.168.178.51</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||
|
|
@ -22,11 +22,15 @@
|
|||
</entry>
|
||||
<entry>
|
||||
<key>enableLocalChanges</key>
|
||||
<value>true</value>
|
||||
<value>false</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>enableLocalTaskScoring</key>
|
||||
<value>false</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>lastVersionNumber</key>
|
||||
<value></value>
|
||||
<value>1.0</value>
|
||||
</entry>
|
||||
<entry>
|
||||
<key>lastVersionCode</key>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ interface TaskRepository : BaseRepository {
|
|||
fun retrieveTasks(userId: String, tasksOrder: TasksOrder): Flowable<TaskList>
|
||||
fun retrieveTasks(userId: String, tasksOrder: TasksOrder, dueDate: Date): Flowable<TaskList>
|
||||
|
||||
fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean): Flowable<TaskScoringResult?>
|
||||
fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean): Maybe<TaskScoringResult?>
|
||||
fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?>
|
||||
fun taskChecked(user: User?, taskId: String, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Maybe<TaskScoringResult?>
|
||||
fun scoreChecklistItem(taskId: String, itemId: String): Flowable<Task>
|
||||
|
||||
fun getTask(taskId: String): Flowable<Task>
|
||||
|
|
|
|||
|
|
@ -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<TaskLocalRepository>(localRepository, apiClient, userID), TaskRepository {
|
||||
class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiClient, userID: String, val appConfigManager: AppConfigManager) : BaseRepositoryImpl<TaskLocalRepository>(localRepository, apiClient, userID), TaskRepository {
|
||||
override fun getTasksOfType(taskType: String): Flowable<RealmResults<Task>> = 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<TaskScoringResult?> {
|
||||
override fun taskChecked(user: User?, task: Task, up: Boolean, force: Boolean, notifyFunc: ((TaskScoringResult) -> Unit)?): Flowable<TaskScoringResult?> {
|
||||
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<TaskScoringResult?> {
|
||||
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<TaskScoringResult?> {
|
||||
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<Task> {
|
||||
|
|
|
|||
|
|
@ -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() }
|
||||
|
|
|
|||
|
|
@ -61,4 +61,8 @@ class AppConfigManager {
|
|||
fun testingLevel(): AppTestingLevel {
|
||||
return AppTestingLevel.valueOf(BuildConfig.TESTING_LEVEL)
|
||||
}
|
||||
|
||||
fun enableLocalTaskScoring(): Boolean {
|
||||
return remoteConfig.getBoolean("enableLocalTaskScoring")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<BuyRewardUseCase.RequestValues, TaskScoringResult> {
|
||||
|
||||
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<TaskScoringResult> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<BuyRewardUseCase.RequestValues, TaskScoringResult>(threadExecutor, postExecutionThread) {
|
||||
|
||||
override fun buildUseCaseObservable(requestValues: BuyRewardUseCase.RequestValues): Flowable<TaskScoringResult?> {
|
||||
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
|
||||
}
|
||||
|
|
@ -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<DailyCheckUseCase.RequestValues, TaskScoringResult> {
|
||||
|
||||
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<TaskScoringResult> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<DailyCheckUseCase.RequestValues, TaskScoringResult>(threadExecutor, postExecutionThread) {
|
||||
|
||||
override fun buildUseCaseObservable(requestValues: RequestValues): Flowable<TaskScoringResult?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<HabitScoreUseCase.RequestValues, TaskScoringResult> {
|
||||
|
||||
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<TaskScoringResult> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<HabitScoreUseCase.RequestValues, TaskScoringResult>(threadExecutor, postExecutionThread) {
|
||||
|
||||
override fun buildUseCaseObservable(requestValues: RequestValues): Flowable<TaskScoringResult?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Bitmap?> {
|
||||
|
|
|
|||
|
|
@ -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<String>()
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<TodoCheckUseCase.RequestValues, TaskScoringResult> {
|
||||
|
||||
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<TaskScoringResult> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<TodoCheckUseCase.RequestValues, TaskScoringResult>(threadExecutor, postExecutionThread) {
|
||||
|
||||
override fun buildUseCaseObservable(requestValues: TodoCheckUseCase.RequestValues): Flowable<TaskScoringResult?> {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
package com.habitrpg.android.habitica.models.responses
|
||||
|
||||
enum class TaskDirection(val text: String) {
|
||||
UP("up"),
|
||||
DOWN("down");
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ class TaskDirectionDataTemp {
|
|||
|
||||
var drop: TaskDirectionDataDrop? = null
|
||||
var quest: TaskDirectionDataQuest? = null
|
||||
|
||||
var crit: Float? = null
|
||||
}
|
||||
|
||||
class TaskDirectionDataQuest {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<TaskScoringResult> { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
|
||||
dailyCheckUseCase.observable(DailyCheckUseCase.RequestValues(user, event.Task, !event.Task.completed) { result -> displayTaskScoringResponse(result)})
|
||||
.subscribe(Consumer<TaskScoringResult> { }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
Task.TYPE_TODO -> {
|
||||
todoCheckUseCase.observable(TodoCheckUseCase.RequestValues(user, event.Task, !event.Task.completed))
|
||||
.subscribe(Consumer<TaskScoringResult> { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
|
||||
todoCheckUseCase.observable(TodoCheckUseCase.RequestValues(user, event.Task, !event.Task.completed) { result -> displayTaskScoringResponse(result)})
|
||||
.subscribe(Consumer<TaskScoringResult> { }, 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<TaskScoringResult> { this.displayTaskScoringResponse(it) }, RxErrorHandler.handleEmptyError())
|
||||
habitScoreUseCase.observable(HabitScoreUseCase.RequestValues(user, event.habit, event.Up) { result -> displayTaskScoringResponse(result)})
|
||||
.subscribe(Consumer<TaskScoringResult> { }, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
private fun checkMaintenance() {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@
|
|||
// @Test
|
||||
// public void shouldBeAbleToScoreTaskUp() {
|
||||
// TestSubscriber<TaskDirectionData> 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<TaskDirectionData> testSubscriber = new TestSubscriber<>();
|
||||
// apiClient.postTaskDirection(habit1.getId(), "down")
|
||||
// apiClient.postTaskDirection(habit1.getId(), "DOWN")
|
||||
// .subscribe(testSubscriber);
|
||||
// testSubscriber.awaitTerminalEvent();
|
||||
// testSubscriber.assertNoErrors();
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
Loading…
Reference in a new issue