diff --git a/Habitica/res/layout/activity_task_form.xml b/Habitica/res/layout/activity_task_form.xml index 82f5f0b12..ad3861b50 100644 --- a/Habitica/res/layout/activity_task_form.xml +++ b/Habitica/res/layout/activity_task_form.xml @@ -66,6 +66,16 @@ android:gravity="top" android:inputType="textCapSentences|textAutoCorrect|textMultiLine"/> + Subscription Status Leave Challenge - Are you sure you want to leave the Challenge ā€œ%sā€? - Remove tasks - Do you want to remove the tasks? + You can choose to keep this Challenge\'s tasks on your personal task board or delete them when you leave + Leave & Keep Tasks + Leave & Delete Tasks Remove Keep My Challenges @@ -1073,4 +1073,13 @@ Use Saddle Hatch your Pet Hatch + Delete Challenge Task? + This is one of %d tasks that are part of the ā€œ%sā€ Challenge. You must leave the Challenge to delete this task. + Leave & Delete Task + Leave & Delete %d Tasks + Broken Challenge + This is one of %d tasks that are part of a Challenge that no longer exists. What would you like to do with these left over tasks? + Keep %d Tasks + Delete %d Tasks + %s Challenge Task diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.kt index 7ef1162ca..463ccd96e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.kt @@ -383,4 +383,7 @@ interface ApiService { @POST("members/transfer-gems") fun transferGems(@Body data: Map): Flowable> + + @POST("tasks/unlink-all/{challengeID}") + fun unlinkAllTasks(@Path("challengeID") challengeID: String?, @Query("keep") keepOption: String): Flowable> } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt index 3ed6fccbe..795a9e4ce 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.kt @@ -258,4 +258,5 @@ interface ApiClient { fun findUsernames(username: String, context: String?, id: String?): Flowable> fun transferGems(giftedID: String, amount: Int): Flowable + fun unlinkAllTasks(challengeID: String?, keepOption: String): Flowable } 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 01026d5ac..05447f8ef 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 @@ -59,4 +59,6 @@ interface TaskRepository : BaseRepository { fun retrieveDailiesFromDate(date: Date): Flowable fun retrieveCompletedTodos(userId: String): Flowable fun syncErroredTasks(): Single> + fun unlinkAllTasks(challengeID: String?, keepOption: String): Flowable + fun getTasksForChallenge(challengeID: String?): Flowable> } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt index 097fdbb91..2e0f91d05 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.kt @@ -332,6 +332,10 @@ class ApiClientImpl//private OnHabitsAPIResult mResultListener; return apiService.buyItem(itemKey, mapOf(Pair("quantity", purchaseQuantity))).compose(configureApiCallObserver()) } + override fun unlinkAllTasks(challengeID: String?, keepOption: String): Flowable { + return apiService.unlinkAllTasks(challengeID, keepOption).compose(configureApiCallObserver()) + } + override fun purchaseItem(type: String, itemKey: String, purchaseQuantity: Int): Flowable { return apiService.purchaseItem(type, itemKey, mapOf(Pair("quantity", purchaseQuantity))).compose(configureApiCallObserver()) } 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 c8cc35aa8..3899118cd 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 @@ -307,4 +307,12 @@ class TaskRepositoryImpl(localRepository: TaskLocalRepository, apiClient: ApiCli } }.toList() } + + override fun unlinkAllTasks(challengeID: String?, keepOption: String): Flowable { + return apiClient.unlinkAllTasks(challengeID, keepOption) + } + + override fun getTasksForChallenge(challengeID: String?): Flowable> { + return localRepository.getTasksForChallenge(challengeID) + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt index eab649202..826bd03f0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/TaskLocalRepository.kt @@ -35,4 +35,5 @@ interface TaskLocalRepository : BaseLocalRepository { fun saveCompletedTodos(userId: String, tasks: MutableCollection) fun getErroredTasks(userID: String): Flowable> fun getUser(userID: String): Flowable + fun getTasksForChallenge(challengeID: String?): Flowable> } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt index 4f6b33ed7..2fb85458d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmTaskLocalRepository.kt @@ -225,7 +225,8 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), .findAll() .asFlowable() .filter { it.isLoaded } - .retry(1) } + .retry(1) + } override fun getUser(userID: String): Flowable { return realm.where(User::class.java) @@ -235,4 +236,13 @@ class RealmTaskLocalRepository(realm: Realm) : RealmBaseLocalRepository(realm), .filter { realmObject -> realmObject.isLoaded && realmObject.isValid && !realmObject.isEmpty() } .map { users -> users.first() } } + + override fun getTasksForChallenge(challengeID: String?): Flowable> { + return realm.where(Task::class.java) + .equalTo("challengeID", challengeID) + .findAll() + .asFlowable() + .filter { it.isLoaded } + .retry(1) + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt index b6b579fa5..5f6cf1bde 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/TaskFormActivity.kt @@ -21,9 +21,7 @@ import androidx.core.view.forEachIndexed import androidx.core.widget.NestedScrollView import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.components.UserComponent -import com.habitrpg.android.habitica.data.TagRepository -import com.habitrpg.android.habitica.data.TaskRepository -import com.habitrpg.android.habitica.data.UserRepository +import com.habitrpg.android.habitica.data.* import com.habitrpg.android.habitica.extensions.OnChangeTextWatcher import com.habitrpg.android.habitica.extensions.addCancelButton import com.habitrpg.android.habitica.extensions.dpToPx @@ -31,6 +29,7 @@ import com.habitrpg.android.habitica.extensions.getThemeColor import com.habitrpg.android.habitica.helpers.RxErrorHandler import com.habitrpg.android.habitica.helpers.TaskAlarmManager import com.habitrpg.android.habitica.models.Tag +import com.habitrpg.android.habitica.models.social.Challenge import com.habitrpg.android.habitica.models.tasks.HabitResetOption import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.models.user.Stats @@ -55,6 +54,8 @@ class TaskFormActivity : BaseActivity() { lateinit var tagRepository: TagRepository @Inject lateinit var taskAlarmManager: TaskAlarmManager + @Inject + lateinit var challengeRepository: ChallengeRepository private val toolbar: Toolbar by bindView(R.id.toolbar) private val scrollView: NestedScrollView by bindView(R.id.scroll_view) @@ -90,6 +91,10 @@ class TaskFormActivity : BaseActivity() { private val tagsTitleView: TextView by bindView(R.id.tags_title) private val tagsWrapper: LinearLayout by bindView(R.id.tags_wrapper) + private val challengeNameView: TextView by bindView(R.id.challenge_name_view) + + private var challenge: Challenge? = null + private var isCreating = true private var isChallengeTask = false private var usesTaskAttributeStats = false @@ -193,6 +198,13 @@ class TaskFormActivity : BaseActivity() { task = it //tintColor = ContextCompat.getColor(this, it.mediumTaskColor) fillForm(it) + task?.challengeID?.let { + compositeSubscription.add(challengeRepository.retrieveChallenge(it).subscribe(Consumer { + challenge = it + challengeNameView.text = getString(R.string.challenge_task_name, it.name) + challengeNameView.visibility = View.VISIBLE + }, RxErrorHandler.handleEmptyError())) + } }, RxErrorHandler.handleEmptyError())) } bundle.containsKey(PARCELABLE_TASK) -> { @@ -464,6 +476,10 @@ class TaskFormActivity : BaseActivity() { } private fun deleteTask() { + if (task?.challengeID?.isNotBlank() == true && task?.challengeBroken?.isNotBlank() != true) { + showChallengeDeleteTask() + return + } val alert = HabiticaAlertDialog(this) alert.setTitle(R.string.are_you_sure) alert.addButton(R.string.delete_task, true) { _, _ -> @@ -476,6 +492,36 @@ class TaskFormActivity : BaseActivity() { alert.show() } + private fun showChallengeDeleteTask() { + compositeSubscription.add(taskRepository.getTasksForChallenge(task?.challengeID).subscribe(Consumer { tasks -> + val taskCount = tasks.size + val alert = HabiticaAlertDialog(this) + alert.setTitle(getString(R.string.delete_challenge_task_title)) + alert.setMessage(getString(R.string.delete_challenge_task_description, taskCount, challenge?.name ?: "")) + alert.addButton(R.string.leave_delete_task, true, true) { _, _ -> + challenge?.let { + compositeSubscription.add(challengeRepository.leaveChallenge(it, "keep-all") + .flatMap { taskRepository.deleteTask(task?.id ?: "") } + .flatMap { userRepository.retrieveUser(true) } + .subscribe(Consumer { + finish() + }, RxErrorHandler.handleEmptyError())) + } + } + alert.addButton(getString(R.string.leave_delete_x_tasks, taskCount), false, true) { _, _ -> + challenge?.let { + compositeSubscription.add(challengeRepository.leaveChallenge(it, "remove-all") + .flatMap { userRepository.retrieveUser(true) } + .subscribe(Consumer { + finish() + }, RxErrorHandler.handleEmptyError())) + } + } + alert.setExtraCloseButtonVisibility(View.VISIBLE) + alert.show() + }, RxErrorHandler.handleEmptyError())) + } + private fun dismissKeyboard() { val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager val currentFocus = currentFocus diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/challenges/ChallengeTasksRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/challenges/ChallengeTasksRecyclerViewAdapter.kt index d1f32b9e3..07bb34cb9 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/challenges/ChallengeTasksRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/social/challenges/ChallengeTasksRecyclerViewAdapter.kt @@ -63,16 +63,16 @@ class ChallengeTasksRecyclerViewAdapter(taskFilterHelper: TaskFilterHelper?, lay override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindableViewHolder { val viewHolder: BindableViewHolder = when (viewType) { - TYPE_HABIT -> HabitViewHolder(getContentView(parent, R.layout.habit_item_card), { _, _ -> }) { task -> + TYPE_HABIT -> HabitViewHolder(getContentView(parent, R.layout.habit_item_card), { _, _ -> }, { }) { task -> taskOpenEventsSubject.onNext(task) } - TYPE_DAILY -> DailyViewHolder(getContentView(parent, R.layout.daily_item_card), { _, _ -> }, { _, _ -> }) { task -> + TYPE_DAILY -> DailyViewHolder(getContentView(parent, R.layout.daily_item_card), { _, _ -> }, { _, _ -> }, { }) { task -> taskOpenEventsSubject.onNext(task) } - TYPE_TODO -> TodoViewHolder(getContentView(parent, R.layout.todo_item_card), { _, _ -> }, { _, _ -> }) { task -> + TYPE_TODO -> TodoViewHolder(getContentView(parent, R.layout.todo_item_card), { _, _ -> }, { _, _ -> }, { }) { task -> taskOpenEventsSubject.onNext(task) } - TYPE_REWARD -> RewardViewHolder(getContentView(parent, R.layout.reward_item_card), { _, _ -> }) { task -> + TYPE_REWARD -> RewardViewHolder(getContentView(parent, R.layout.reward_item_card), { _, _ -> }, { }) { task -> taskOpenEventsSubject.onNext(task) } TYPE_ADD_ITEM -> AddItemViewHolder(getContentView(parent, R.layout.challenge_add_task_item), addItemSubject) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt index 147ec2b88..9535f6986 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.kt @@ -12,7 +12,9 @@ class DailiesRecyclerViewHolder(data: OrderedRealmCollection?, autoUpdate: override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DailyViewHolder = DailyViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, - { task, item -> checklistItemScoreSubject.onNext(Pair(task, item))}) { + { task, item -> checklistItemScoreSubject.onNext(Pair(task, item))}, { task -> taskOpenEventsSubject.onNext(task) + }) { + task -> brokenTaskEventsSubject.onNext(task) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt index 1e41f002f..715e42566 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.kt @@ -10,7 +10,9 @@ class HabitsRecyclerViewAdapter(data: OrderedRealmCollection?, autoUpdate: override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HabitViewHolder = - HabitViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }) { + HabitViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, { task -> taskOpenEventsSubject.onNext(task) + }) { + task -> brokenTaskEventsSubject.onNext(task) } } \ No newline at end of file diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt index 40e18dc74..92e8926ae 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RealmBaseTasksRecyclerViewAdapter.kt @@ -112,6 +112,8 @@ abstract class RealmBaseTasksRecyclerViewAdapter( override val checklistItemScoreEvents: Flowable> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP) protected var taskOpenEventsSubject = PublishSubject.create() override val taskOpenEvents: Flowable = taskOpenEventsSubject.toFlowable(BackpressureStrategy.DROP) + protected var brokenTaskEventsSubject = PublishSubject.create() + override val brokenTaskEvents: Flowable = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP) private val isDataValid: Boolean get() = data?.isValid ?: false diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt index deda9fe5e..304ef4c40 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.kt @@ -30,6 +30,8 @@ class RewardsRecyclerViewAdapter(private var customRewards: OrderedRealmCollecti override val checklistItemScoreEvents: Flowable> = checklistItemScoreSubject.toFlowable(BackpressureStrategy.DROP) private var taskOpenEventsSubject = PublishSubject.create() override val taskOpenEvents: Flowable = taskOpenEventsSubject.toFlowable(BackpressureStrategy.LATEST) + protected var brokenTaskEventsSubject = PublishSubject.create() + override val brokenTaskEvents: Flowable = brokenTaskEventsSubject.toFlowable(BackpressureStrategy.DROP) private var purchaseCardSubject = PublishSubject.create() val purchaseCardEvents: Flowable = purchaseCardSubject.toFlowable(BackpressureStrategy.LATEST) @@ -64,8 +66,10 @@ class RewardsRecyclerViewAdapter(private var customRewards: OrderedRealmCollecti override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return if (viewType == VIEWTYPE_CUSTOM_REWARD) { - RewardViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }) { + RewardViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, { task -> taskOpenEventsSubject.onNext(task) + }) { + task -> brokenTaskEventsSubject.onNext(task) } } else { val viewHolder = ShopItemViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.row_shopitem, parent, false)) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt index 7f9a4b5db..1c2a0707e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TaskRecyclerViewAdapter.kt @@ -27,4 +27,5 @@ interface TaskRecyclerViewAdapter { val taskScoreEvents: Flowable> val checklistItemScoreEvents: Flowable> val taskOpenEvents: Flowable + val brokenTaskEvents: Flowable } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt index 2afcc131d..f735ca531 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.kt @@ -12,8 +12,10 @@ class TodosRecyclerViewAdapter(data: OrderedRealmCollection?, autoUpdate: override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder = TodoViewHolder(getContentView(parent), { task, direction -> taskScoreEventsSubject.onNext(Pair(task, direction)) }, - { task, item -> checklistItemScoreSubject.onNext(Pair(task, item))}) { - task -> taskOpenEventsSubject.onNext(task) - } + { task, item -> checklistItemScoreSubject.onNext(Pair(task, item))}, { + task -> taskOpenEventsSubject.onNext(task) + }) { + task -> brokenTaskEventsSubject.onNext(task) + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt index 77a260823..caa1a8649 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/challenges/ChallengeDetailFragment.kt @@ -353,34 +353,16 @@ class ChallengeDetailFragment: BaseMainFragment() { val context = context ?: return val alert = HabiticaAlertDialog(context) alert.setTitle(this.getString(R.string.challenge_leave_title)) - alert.setMessage(this.getString(R.string.challenge_leave_text, challenge?.name ?: "")) - alert.addButton(R.string.yes, true) { dialog, _ -> - dialog.dismiss() - showRemoveTasksDialog(Consumer { keepTasks -> - val challenge = challenge ?: return@Consumer - challengeRepository.leaveChallenge(challenge, keepTasks).subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) - }) + alert.setMessage(this.getString(R.string.challenge_leave_description)) + alert.addButton(R.string.leave_keep_tasks, true) { dialog, _ -> + val challenge = challenge ?: return@addButton + challengeRepository.leaveChallenge(challenge, "keep-all").subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) } - alert.addButton(R.string.no, false) { dialog, _ -> - dialog.dismiss() + alert.addButton(R.string.leave_delte_tasks, false, true) { dialog, _ -> + val challenge = challenge ?: return@addButton + challengeRepository.leaveChallenge(challenge, "remove-all").subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) } + alert.setExtraCloseButtonVisibility(View.VISIBLE) alert.show() } - - private fun showRemoveTasksDialog(callback: Consumer) { - context?.let { - val alert = HabiticaAlertDialog(it) - alert.setTitle(this.getString(R.string.challenge_remove_tasks_title)) - alert.setMessage(this.getString(R.string.challenge_remove_tasks_text)) - alert.addButton(R.string.remove_tasks, false) { dialog, _ -> - callback.accept("remove-all") - dialog.dismiss() - } - alert.addButton(R.string.keep_tasks, false) { dialog, _ -> - callback.accept("keep-all") - dialog.dismiss() - } - alert.show() - } - } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt index 6fe7dab3e..f8c0aa044 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/RewardsRecyclerviewFragment.kt @@ -61,6 +61,7 @@ class RewardsRecyclerviewFragment : TaskRecyclerViewFragment() { val intent = Intent(activity, SkillMemberActivity::class.java) startActivityForResult(intent, 11) }, RxErrorHandler.handleEmptyError())?.let { compositeSubscription.add(it) } + recyclerAdapter?.brokenTaskEvents?.subscribeWithErrorHandler(Consumer { showBrokenChallengeDialog(it) })?.let { compositeSubscription.add(it) } } override fun getLayoutManager(context: Context?): LinearLayoutManager { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt index 7308bd439..f513ef811 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.kt @@ -38,6 +38,7 @@ import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator import com.habitrpg.android.habitica.ui.viewHolders.tasks.BaseTaskViewHolder import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar +import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer import java.util.* @@ -262,6 +263,7 @@ open class TaskRecyclerViewFragment : BaseFragment(), androidx.swiperefreshlayou recyclerAdapter?.checklistItemScoreEvents ?.flatMap { taskRepository.scoreChecklistItem(it.first.id ?: "", it.second.id ?: "") }?.subscribeWithErrorHandler(Consumer {})?.let { compositeSubscription.add(it) } + recyclerAdapter?.brokenTaskEvents?.subscribeWithErrorHandler(Consumer { showBrokenChallengeDialog(it) })?.let { compositeSubscription.add(it) } } val bottomPadding = (binding.recyclerView.paddingBottom + TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 60f, resources.displayMetrics)).toInt() @@ -287,6 +289,25 @@ open class TaskRecyclerViewFragment : BaseFragment(), androidx.swiperefreshlayou } } + protected fun showBrokenChallengeDialog(task: Task) { + context?.let { + taskRepository.getTasksForChallenge(task.challengeID).subscribe(Consumer { tasks -> + val taskCount = tasks.size + val dialog = HabiticaAlertDialog(it) + dialog.setTitle(R.string.broken_challenge) + dialog.setMessage(it.getString(R.string.broken_challenge_description, taskCount)) + dialog.addButton(it.getString(R.string.keep_x_tasks, taskCount), true) { _, _ -> + taskRepository.unlinkAllTasks(task.challengeID, "keep-all").subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + } + dialog.addButton(it.getString(R.string.delete_x_tasks, taskCount), false, true) { _, _ -> + taskRepository.unlinkAllTasks(task.challengeID, "remove-all").subscribe(Consumer {}, RxErrorHandler.handleEmptyError()) + } + dialog.setExtraCloseButtonVisibility(View.VISIBLE) + dialog.show() + }, RxErrorHandler.handleEmptyError()) + } + } + private fun setEmptyLabels() { if (this.classType != null) { binding.recyclerView.setEmptyView(binding.emptyView) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt index e1d560367..ff9afb9e3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.kt @@ -20,7 +20,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -abstract class BaseTaskViewHolder constructor(itemView: View, var scoreTaskFunc: ((Task, TaskDirection) -> Unit), var openTaskFunc: ((Task) -> Unit)) : BindableViewHolder(itemView), View.OnClickListener { +abstract class BaseTaskViewHolder constructor(itemView: View, var scoreTaskFunc: ((Task, TaskDirection) -> Unit), var openTaskFunc: ((Task) -> Unit), var brokenTaskFunc: ((Task) -> Unit)) : BindableViewHolder(itemView), View.OnClickListener { var task: Task? = null @@ -80,6 +80,11 @@ abstract class BaseTaskViewHolder constructor(itemView: View, var scoreTaskFunc: //titleTextView.movementMethod = LinkMovementMethod.getInstance() expandNotesButton?.setOnClickListener { expandTask() } + iconViewChallenge?.setOnClickListener { + task?.let { t -> + if (task?.challengeBroken?.isNotBlank() == true) brokenTaskFunc(t) + } + } notesTextView?.addEllipsesListener(object : EllipsisTextView.EllipsisListener { override fun ellipsisStateChanged(ellipses: Boolean) { GlobalScope.launch(Dispatchers.Main.immediate) { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt index 36b582773..64bee280d 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.kt @@ -25,7 +25,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer import io.reactivex.schedulers.Schedulers -abstract class ChecklistedViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), var scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc), CompoundButton.OnCheckedChangeListener { +abstract class ChecklistedViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), var scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit), brokenTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc), CompoundButton.OnCheckedChangeListener { private val checkboxHolder: ViewGroup by bindView(itemView, R.id.checkBoxHolder) internal val checkbox: CheckBox by bindView(itemView, R.id.checkBox) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt index 366ec5d80..003fd6884 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.kt @@ -10,7 +10,7 @@ import com.habitrpg.android.habitica.ui.helpers.bindView import java.text.DateFormat import java.util.* -class DailyViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit)) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc) { +class DailyViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit), brokenTaskFunc: ((Task) -> Unit)) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc, brokenTaskFunc) { private val streakTextView: TextView by bindView(itemView, R.id.streakTextView) private val reminderTextView: TextView by bindView(itemView, R.id.reminder_textview) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt index 3346c61fb..9d5aecf8c 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.kt @@ -10,7 +10,7 @@ import com.habitrpg.android.habitica.models.responses.TaskDirection import com.habitrpg.android.habitica.models.tasks.Task import com.habitrpg.android.habitica.ui.helpers.bindView -class HabitViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), openTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc) { +class HabitViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), openTaskFunc: ((Task) -> Unit), brokenTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc) { private val btnPlusWrapper: FrameLayout by bindView(itemView, R.id.btnPlusWrapper) private val btnPlusIconView: ImageView by bindView(itemView, R.id.btnPlusIconView) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt index 9bc563cda..bc2875d51 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.kt @@ -13,7 +13,7 @@ import com.habitrpg.android.habitica.ui.ItemDetailDialog import com.habitrpg.android.habitica.ui.helpers.bindView import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper -class RewardViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), openTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc) { +class RewardViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), openTaskFunc: ((Task) -> Unit), brokenTaskFunc: ((Task) -> Unit)) : BaseTaskViewHolder(itemView, scoreTaskFunc, openTaskFunc, brokenTaskFunc) { private val buyButton: View by bindView(itemView, R.id.buyButton) internal val priceLabel: TextView by bindView(itemView, R.id.priceLabel) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt index d7a2fe5f6..240e90203 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.kt @@ -8,7 +8,7 @@ import com.habitrpg.android.habitica.models.tasks.Task import java.text.DateFormat -class TodoViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit)) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc) { +class TodoViewHolder(itemView: View, scoreTaskFunc: ((Task, TaskDirection) -> Unit), scoreChecklistItemFunc: ((Task, ChecklistItem) -> Unit), openTaskFunc: ((Task) -> Unit), brokenTaskFunc: ((Task) -> Unit)) : ChecklistedViewHolder(itemView, scoreTaskFunc, scoreChecklistItemFunc, openTaskFunc, brokenTaskFunc) { private val dateFormatter: DateFormat = android.text.format.DateFormat.getDateFormat(context)