diff --git a/uhabits-android/src/main/AndroidManifest.xml b/uhabits-android/src/main/AndroidManifest.xml
index 1d9dc6620..1f3aba1aa 100644
--- a/uhabits-android/src/main/AndroidManifest.xml
+++ b/uhabits-android/src/main/AndroidManifest.xml
@@ -42,6 +42,14 @@
android:value=".activities.habits.list.ListHabitsActivity" />
+
+
+
+
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/HabitGroupPickerDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/HabitGroupPickerDialog.kt
new file mode 100644
index 000000000..aea309d83
--- /dev/null
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/HabitGroupPickerDialog.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2016-2021 Álinson Santos Xavier
+ *
+ * This file is part of Loop Habit Tracker.
+ *
+ * Loop Habit Tracker is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * Loop Habit Tracker is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+
+package org.isoron.uhabits.activities.habits.list
+
+import android.app.Activity
+import android.os.Bundle
+import android.widget.ArrayAdapter
+import android.widget.ListView
+import android.widget.TextView
+import org.isoron.uhabits.HabitsApplication
+import org.isoron.uhabits.R
+import org.isoron.uhabits.activities.AndroidThemeSwitcher
+import org.isoron.uhabits.core.commands.AddToGroupCommand
+import org.isoron.uhabits.core.models.Habit
+import org.isoron.uhabits.core.models.HabitGroupList
+import org.isoron.uhabits.core.models.HabitList
+import org.isoron.uhabits.inject.HabitsApplicationComponent
+
+class HabitGroupPickerDialog : Activity() {
+
+ private lateinit var habitGroupList: HabitGroupList
+ private lateinit var habitList: HabitList
+ private lateinit var selected: List
+ private lateinit var component: HabitsApplicationComponent
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ component = (applicationContext as HabitsApplication).component
+ AndroidThemeSwitcher(this, component.preferences).apply()
+ habitList = component.habitList
+ habitGroupList = component.habitGroupList
+
+ val selectedIds = intent.getLongArrayExtra("selected")!!
+ selected = selectedIds.map { id ->
+ habitList.getById(id) ?: habitGroupList.getHabitByID(id)!!
+ }
+
+ val groupIds = ArrayList()
+ val groupNames = ArrayList()
+
+ for (hgr in habitGroupList) {
+ if (hgr.isArchived) continue
+ groupIds.add(hgr.id!!)
+ groupNames.add(hgr.name)
+ }
+
+ if (groupNames.isEmpty()) {
+ setContentView(R.layout.widget_empty_activity)
+ findViewById(R.id.message).setText(R.string.no_habit_groups)
+ return
+ }
+
+ setContentView(R.layout.widget_configure_activity)
+ val listView = findViewById(R.id.listView)
+
+ with(listView) {
+ adapter = ArrayAdapter(
+ context,
+ android.R.layout.simple_list_item_1,
+ groupNames
+ )
+ setOnItemClickListener { parent, view, position, id ->
+ performTransfer(groupIds[position])
+ }
+ }
+ }
+ private fun performTransfer(toGroupId: Long) {
+ val hgr = habitGroupList.getById(toGroupId)!!
+ selected = selected.filter { it.groupId != hgr.id }
+ component.commandRunner.run(
+ AddToGroupCommand(habitList, hgr, selected)
+ )
+ finish()
+ }
+}
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt
index abfa0e48f..8feb12748 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt
@@ -185,6 +185,11 @@ class ListHabitsScreen
activity.startActivity(intent)
}
+ override fun showHabitGroupPickerDialog(selected: List) {
+ val intent = intentFactory.startHabitGroupPickerActivity(activity, selected)
+ activity.startActivity(intent)
+ }
+
override fun showFAQScreen() {
val intent = intentFactory.viewFAQ(activity)
activity.startActivity(intent)
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.kt
index ddd9a3b58..35c5563bc 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsSelectionMenu.kt
@@ -76,6 +76,7 @@ class ListHabitsSelectionMenu @Inject constructor(
val itemArchive = menu.findItem(R.id.action_archive_habit)
val itemUnarchive = menu.findItem(R.id.action_unarchive_habit)
val itemRemoveFromGroup = menu.findItem(R.id.action_remove_from_group)
+ val itemAddToGroup = menu.findItem(R.id.action_add_to_group)
val itemNotify = menu.findItem(R.id.action_notify)
itemColor.isVisible = true
@@ -83,6 +84,7 @@ class ListHabitsSelectionMenu @Inject constructor(
itemArchive.isVisible = behavior.canArchive()
itemUnarchive.isVisible = behavior.canUnarchive()
itemRemoveFromGroup.isVisible = behavior.areSubHabits()
+ itemAddToGroup.isVisible = behavior.areHabits()
itemNotify.isVisible = prefs.isDeveloper
activeActionMode?.title = (listAdapter.selectedHabits.size + listAdapter.selectedHabitGroups.size).toString()
return true
@@ -113,6 +115,11 @@ class ListHabitsSelectionMenu @Inject constructor(
return true
}
+ R.id.action_add_to_group -> {
+ behavior.onAddToGroup()
+ return true
+ }
+
R.id.action_delete -> {
behavior.onDeleteHabits()
return true
diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentFactory.kt
index b6c6b9034..b426d9864 100644
--- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentFactory.kt
+++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentFactory.kt
@@ -26,6 +26,7 @@ import org.isoron.uhabits.R
import org.isoron.uhabits.activities.about.AboutActivity
import org.isoron.uhabits.activities.habits.edit.EditHabitActivity
import org.isoron.uhabits.activities.habits.edit.EditHabitGroupActivity
+import org.isoron.uhabits.activities.habits.list.HabitGroupPickerDialog
import org.isoron.uhabits.activities.habits.show.ShowHabitActivity
import org.isoron.uhabits.activities.habits.show.ShowHabitGroupActivity
import org.isoron.uhabits.activities.intro.IntroActivity
@@ -124,4 +125,11 @@ class IntentFactory
intent.putExtra("habitGroupId", habitGroup.id)
return intent
}
+
+ fun startHabitGroupPickerActivity(context: Context, selected: List): Intent {
+ val intent = Intent(context, HabitGroupPickerDialog::class.java)
+ val ids = selected.map { it.id!! }.toLongArray()
+ intent.putExtra("selected", ids)
+ return intent
+ }
}
diff --git a/uhabits-android/src/main/res/menu/list_habits_selection.xml b/uhabits-android/src/main/res/menu/list_habits_selection.xml
index 4a3a986b5..3264edb19 100644
--- a/uhabits-android/src/main/res/menu/list_habits_selection.xml
+++ b/uhabits-android/src/main/res/menu/list_habits_selection.xml
@@ -41,6 +41,11 @@
android:title="@string/unarchive"
app:showAsAction="never"/>
+
+
- Archive
Unarchive
Remove from group
+ Add to group
Add habit
Change color
Habit created
@@ -239,4 +240,5 @@
Extend day a few hours past midnight
Wait until 3:00 AM to show a new day. Useful if you typically go to sleep after midnight. Requires app restart.
Group contains no habits.
+ No habit groups
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/AddToGroupCommand.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/AddToGroupCommand.kt
new file mode 100644
index 000000000..aaf014f5b
--- /dev/null
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/AddToGroupCommand.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2016-2021 Álinson Santos Xavier
+ *
+ * This file is part of Loop Habit Tracker.
+ *
+ * Loop Habit Tracker is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * Loop Habit Tracker is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see .
+ */
+package org.isoron.uhabits.core.commands
+
+import org.isoron.uhabits.core.models.Habit
+import org.isoron.uhabits.core.models.HabitGroup
+import org.isoron.uhabits.core.models.HabitList
+
+data class AddToGroupCommand(
+ val habitList: HabitList,
+ val hgr: HabitGroup,
+ val selected: List
+) : Command {
+ override fun run() {
+ for (h in selected) {
+ val oldGroup = h.group
+ (oldGroup?.habitList ?: habitList).remove(h)
+ h.groupId = hgr.id
+ h.groupUUID = hgr.uuid
+ h.group = hgr
+ hgr.habitList.add(h)
+ }
+ }
+}
diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt
index 9f81cb487..7ee8d3d58 100644
--- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt
+++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsSelectionMenuBehavior.kt
@@ -65,6 +65,10 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
return (adapter.getSelectedHabits().all { it.isSubHabit() })
}
+ fun areHabits(): Boolean {
+ return adapter.getSelectedHabitGroups().isEmpty()
+ }
+
fun onArchiveHabits() {
commandRunner.run(ArchiveHabitsCommand(habitList, adapter.getSelectedHabits()))
commandRunner.run(ArchiveHabitGroupsCommand(habitGroupList, adapter.getSelectedHabitGroups()))
@@ -142,6 +146,12 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
adapter.clearSelection()
}
+ fun onAddToGroup() {
+ adapter.performRemove(adapter.getSelectedHabits())
+ screen.showHabitGroupPickerDialog(adapter.getSelectedHabits())
+ adapter.clearSelection()
+ }
+
interface Adapter {
fun clearSelection()
fun getSelectedHabits(): List
@@ -164,5 +174,6 @@ class ListHabitsSelectionMenuBehavior @Inject constructor(
fun showEditHabitsScreen(selected: List)
fun showEditHabitGroupScreen(selected: List)
+ fun showHabitGroupPickerDialog(selected: List)
}
}