From 022ad81290521924225f511e597337bd4b08d6c9 Mon Sep 17 00:00:00 2001 From: Hafiz Date: Tue, 2 Aug 2022 00:16:03 -0400 Subject: [PATCH 1/3] Show all to-dos and reset after cron --- .../ui/activities/TaskListActivity.kt | 7 +- .../habitica/ui/viewmodels/RYAViewModel.kt | 5 + .../ui/viewmodels/TaskListViewModel.kt | 113 +++++++++++++++--- 3 files changed, 110 insertions(+), 15 deletions(-) diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt index e27ecbda2..67304fcef 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt @@ -67,7 +67,9 @@ class TaskListActivity : BaseActivity Unit) { + //Clear shared pref values for saved to-do tasks + sharedPreferences.edit { putString("to_do_tasks", null) } viewModelScope.launch(exceptionBuilder.userFacing(this)) { appStateManager.startLoading() for (task in tasksToComplete) { diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt index a69ff7478..28f0573a9 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt @@ -1,9 +1,13 @@ package com.habitrpg.wearos.habitica.ui.viewmodels +import android.content.SharedPreferences +import androidx.core.content.edit import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import com.habitrpg.common.habitica.models.responses.TaskDirection import com.habitrpg.common.habitica.models.responses.TaskScoringResult import com.habitrpg.common.habitica.models.tasks.TaskType @@ -17,6 +21,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch +import java.lang.reflect.Type +import java.util.ArrayList import javax.inject.Inject @HiltViewModel @@ -24,26 +30,19 @@ class TaskListViewModel @Inject constructor( savedStateHandle: SavedStateHandle, taskRepository: TaskRepository, userRepository: UserRepository, + val sharedPreferences: SharedPreferences, exceptionBuilder: ExceptionHandlerBuilder, appStateManager: AppStateManager ) : BaseViewModel(userRepository, taskRepository, exceptionBuilder, appStateManager) { + private val gson = Gson() + private val tasksString = sharedPreferences.getString("to_do_tasks", null) val taskType = TaskType.from(savedStateHandle.get("task_type")) val taskCount = MutableLiveData(0) val tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT) .map { - if (taskType == TaskType.DAILY || taskType == TaskType.TODO) { - val taskList: MutableList = it.filter { it.isDue == true || it.type == TaskType.TODO }.sortedBy { it.completed }.toMutableList() - val firstCompletedIndex = taskList.indexOfFirst { it is Task && it.completed } - if (firstCompletedIndex >= 0) { - // since this is the index of the first completed task, this is also the number of incomplete tasks - taskCount.value = firstCompletedIndex - taskList.add(firstCompletedIndex, "Done today") - } else { - taskCount.value = taskList.size - } - taskList - } else { - taskCount.value = it.size - it + when(taskType) { + TaskType.DAILY -> mapDaily(it) + TaskType.TODO -> mapTodos(it) + else -> map(it) } } .asLiveData() @@ -65,4 +64,90 @@ class TaskListViewModel @Inject constructor( onResult(result) } } + + private fun map(tasks: List): List { + taskCount.value = tasks.size + return tasks + } + + private fun mapDaily(tasks: List): MutableList { + val taskList: MutableList = tasks.filter { it.isDue == true || it.type == TaskType.TODO }.sortedBy { it.completed }.toMutableList() + val firstCompletedIndex = taskList.indexOfFirst { it is Task && it.completed } + if (firstCompletedIndex >= 0) { + // since this is the index of the first completed task, this is also the number of incomplete tasks + taskCount.value = firstCompletedIndex + taskList.add(firstCompletedIndex, "Done today") + } else { + taskCount.value = taskList.size + } + return taskList + } + + private fun getCurrentTasks(): List? { + val gson = Gson() + val data = mutableListOf() + val tasksString = sharedPreferences.getString("to_do_tasks", null) + if (tasksString != null) { + val type: Type = object : TypeToken?>() {}.type + val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList + val list = savedCurrentTasks.sortedBy { it.completed } + val firstCompletedIndex = list.indexOfFirst { it.completed } + return if (firstCompletedIndex >= 0) { + // since this is the index of the first completed task, this is also the number of incomplete tasks + taskCount.value = firstCompletedIndex + data.addAll(list) + data.add(firstCompletedIndex, "Done today") + data + } else { + savedCurrentTasks + } + } + return null + } + + private fun mapTodos(tasks: List): List? { + saveCurrentTasks(tasks) + return getCurrentTasks() + } + + private fun saveCurrentTasks(tasks: List) { + val taskList = mutableListOf() + val type: Type = object : TypeToken?>() {}.type + if (tasksString != null) { + val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList + if (!savedCurrentTasks.isNullOrEmpty()) { + for (task in tasks) { + if (!savedCurrentTasks.contains(task)) { + taskList.add(task) + } + } + } + } else { + taskList.addAll(tasks) + } + if (!taskList.isNullOrEmpty()) { + sharedPreferences.edit { + putString("to_do_tasks", gson.toJson(taskList)) + } + } + } + + fun setCurrentToDoAsComplete(currentTask: Task) { + val gson = Gson() + val type: Type = object : TypeToken?>() {}.type + if (tasksString != null) { + val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList + if (!savedCurrentTasks.isNullOrEmpty()) { + savedCurrentTasks.let { tasks -> + val task = tasks[tasks.indexOf(currentTask)] + task.completed = !task.completed + tasks[tasks.indexOf(currentTask)] = task + sharedPreferences.edit { + putString("to_do_tasks", gson.toJson(tasks)) + } + } + } + } + } + } \ No newline at end of file From 7e808c8c859e3ca34ff25bddd832be6a56e02c4e Mon Sep 17 00:00:00 2001 From: Hafiz Date: Tue, 2 Aug 2022 00:20:07 -0400 Subject: [PATCH 2/3] Update method names --- .../wearos/habitica/ui/viewmodels/TaskListViewModel.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt index 28f0573a9..dfc6f4f99 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/viewmodels/TaskListViewModel.kt @@ -83,7 +83,7 @@ class TaskListViewModel @Inject constructor( return taskList } - private fun getCurrentTasks(): List? { + private fun getCurrentToDos(): List? { val gson = Gson() val data = mutableListOf() val tasksString = sharedPreferences.getString("to_do_tasks", null) @@ -106,11 +106,11 @@ class TaskListViewModel @Inject constructor( } private fun mapTodos(tasks: List): List? { - saveCurrentTasks(tasks) - return getCurrentTasks() + saveCurrentToDos(tasks) + return getCurrentToDos() } - private fun saveCurrentTasks(tasks: List) { + private fun saveCurrentToDos(tasks: List) { val taskList = mutableListOf() val type: Type = object : TypeToken?>() {}.type if (tasksString != null) { From 358b66d48b3ee8f431cdb86d38b38c8529ca2bc0 Mon Sep 17 00:00:00 2001 From: Hafiz Date: Tue, 2 Aug 2022 10:52:56 -0400 Subject: [PATCH 3/3] Update completedToDo methods ty phillip --- .../wearos/habitica/modules/AppModule.kt | 23 ++-- .../ui/activities/TaskListActivity.kt | 3 - .../ui/viewmodels/TaskListViewModel.kt | 110 +++++++----------- .../util/HabiticaCoroutineExceptionhandler.kt | 4 +- 4 files changed, 60 insertions(+), 80 deletions(-) diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt index c1dab7e00..74e670bc2 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/modules/AppModule.kt @@ -45,19 +45,24 @@ class AppModule { } @Provides - fun providesConverterFactory(): Converter.Factory { + fun providesConverterFactory(moshi: Moshi): Converter.Factory { return MoshiConverterFactory.create( - Moshi.Builder() - .add(WrappedTasklistAdapter()) - .add(customDateAdapter) - .add(FrequencyAdapter()) - .add(TaskTypeAdapter()) - .add(AttributeAdapter()) - .addLast(KotlinJsonAdapterFactory()) - .build() + moshi ).asLenient() } + @Provides + fun providesMoshi(): Moshi { + return Moshi.Builder() + .add(WrappedTasklistAdapter()) + .add(customDateAdapter) + .add(FrequencyAdapter()) + .add(TaskTypeAdapter()) + .add(AttributeAdapter()) + .addLast(KotlinJsonAdapterFactory()) + .build() + } + @Provides @Singleton fun providesApiHClient( diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt index 67304fcef..d3fefdfac 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/ui/activities/TaskListActivity.kt @@ -82,9 +82,6 @@ class TaskListActivity : BaseActivity> = moshi.adapter(type) val taskType = TaskType.from(savedStateHandle.get("task_type")) val taskCount = MutableLiveData(0) + val completedToDos: MutableList by lazy { + val tasksString = sharedPreferences.getString("to_do_tasks", null) ?: return@lazy mutableListOf() + return@lazy moshiAdapter.fromJson(tasksString) ?: mutableListOf() + } val tasks = taskRepository.getTasks(taskType ?: TaskType.HABIT) .map { when(taskType) { @@ -50,7 +58,22 @@ class TaskListViewModel @Inject constructor( .asLiveData() fun scoreTask(task: Task, direction: TaskDirection, onResult: (TaskScoringResult?) -> Unit) { - viewModelScope.launch(exceptionBuilder.userFacing(this)) { + if (taskType == TaskType.TODO) { + if (direction == TaskDirection.UP) { + completedToDos.add(task) + } else { + completedToDos.remove(task) + } + } + viewModelScope.launch(exceptionBuilder.userFacing(this) { + if (taskType == TaskType.TODO) { + if (direction == TaskDirection.UP) { + completedToDos.remove(task) + } else { + completedToDos.add(task) + } + } + }) { val result = taskRepository.scoreTask( userRepository.getUser().first(), task, @@ -83,70 +106,25 @@ class TaskListViewModel @Inject constructor( return taskList } - private fun getCurrentToDos(): List? { - val gson = Gson() - val data = mutableListOf() - val tasksString = sharedPreferences.getString("to_do_tasks", null) - if (tasksString != null) { - val type: Type = object : TypeToken?>() {}.type - val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList - val list = savedCurrentTasks.sortedBy { it.completed } - val firstCompletedIndex = list.indexOfFirst { it.completed } - return if (firstCompletedIndex >= 0) { - // since this is the index of the first completed task, this is also the number of incomplete tasks - taskCount.value = firstCompletedIndex - data.addAll(list) - data.add(firstCompletedIndex, "Done today") - data - } else { - savedCurrentTasks - } - } - return null + override fun onCleared() { + saveCurrentToDos() + super.onCleared() } - private fun mapTodos(tasks: List): List? { - saveCurrentToDos(tasks) - return getCurrentToDos() + private fun mapTodos(tasks: List): List { + val taskList: MutableList = tasks.filter { !it.completed }.toMutableList() + taskCount.value = taskList.size + if (completedToDos.isNotEmpty()) { + taskList.add("Done today") + taskList.addAll(completedToDos) + } + + return taskList } - private fun saveCurrentToDos(tasks: List) { - val taskList = mutableListOf() - val type: Type = object : TypeToken?>() {}.type - if (tasksString != null) { - val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList - if (!savedCurrentTasks.isNullOrEmpty()) { - for (task in tasks) { - if (!savedCurrentTasks.contains(task)) { - taskList.add(task) - } - } - } - } else { - taskList.addAll(tasks) - } - if (!taskList.isNullOrEmpty()) { - sharedPreferences.edit { - putString("to_do_tasks", gson.toJson(taskList)) - } - } - } - - fun setCurrentToDoAsComplete(currentTask: Task) { - val gson = Gson() - val type: Type = object : TypeToken?>() {}.type - if (tasksString != null) { - val savedCurrentTasks = gson.fromJson(tasksString, type) as MutableList - if (!savedCurrentTasks.isNullOrEmpty()) { - savedCurrentTasks.let { tasks -> - val task = tasks[tasks.indexOf(currentTask)] - task.completed = !task.completed - tasks[tasks.indexOf(currentTask)] = task - sharedPreferences.edit { - putString("to_do_tasks", gson.toJson(tasks)) - } - } - } + private fun saveCurrentToDos() { + sharedPreferences.edit { + putString("to_do_tasks", moshiAdapter.toJson(completedToDos)) } } diff --git a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/HabiticaCoroutineExceptionhandler.kt b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/HabiticaCoroutineExceptionhandler.kt index a97962e85..b9532eb9f 100644 --- a/wearos/src/main/java/com/habitrpg/wearos/habitica/util/HabiticaCoroutineExceptionhandler.kt +++ b/wearos/src/main/java/com/habitrpg/wearos/habitica/util/HabiticaCoroutineExceptionhandler.kt @@ -18,7 +18,7 @@ class ExceptionHandlerBuilder @Inject constructor(val appStateManager: AppStateM } } - fun userFacing(errorPresenter: ErrorPresenter): CoroutineExceptionHandler { + fun userFacing(errorPresenter: ErrorPresenter, handler: ((Throwable) -> Unit)? = null): CoroutineExceptionHandler { return CoroutineExceptionHandler { _, throwable -> Log.e("Coroutine Error", "Error: ${throwable.cause}", throwable) if (throwable is IOException) { @@ -30,7 +30,7 @@ class ExceptionHandlerBuilder @Inject constructor(val appStateManager: AppStateM DisplayedError(R.drawable.error, it) } } - + handler?.invoke(throwable) appStateManager.endLoading() } }