diff --git a/app/src/main/java/com/itsaky/androidide/actions/sidebar/BuildVariantsSidebarAction.kt b/app/src/main/java/com/itsaky/androidide/actions/sidebar/BuildVariantsSidebarAction.kt
new file mode 100644
index 000000000..8a503f6d9
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/actions/sidebar/BuildVariantsSidebarAction.kt
@@ -0,0 +1,42 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE 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.
+ *
+ * AndroidIDE 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 AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.actions.sidebar
+
+import android.content.Context
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import com.itsaky.androidide.R
+import com.itsaky.androidide.fragments.sidebar.BuildVariantsFragment
+import kotlin.reflect.KClass
+
+/**
+ * Sidebar action for showing the build variants of Android modules in the project.
+ *
+ * @author Akash Yadav
+ */
+class BuildVariantsSidebarAction(context: Context, override val order: Int) :
+ AbstractSidebarAction() {
+
+ override val fragmentClass: KClass = BuildVariantsFragment::class
+ override val id: String = "ide.editor.sidebar.buildVariants"
+
+ init {
+ label = context.getString(R.string.title_build_variants)
+ icon = ContextCompat.getDrawable(context, R.drawable.ic_android)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/adapters/BuildVariantsAdapter.kt b/app/src/main/java/com/itsaky/androidide/adapters/BuildVariantsAdapter.kt
new file mode 100644
index 000000000..11ab53fe2
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/adapters/BuildVariantsAdapter.kt
@@ -0,0 +1,65 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE 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.
+ *
+ * AndroidIDE 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 AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.adapters
+
+import android.view.LayoutInflater
+import android.view.ViewGroup
+import android.widget.ArrayAdapter
+import androidx.recyclerview.widget.RecyclerView
+import com.itsaky.androidide.R
+import com.itsaky.androidide.databinding.LayoutBuildVariantItemBinding
+import com.itsaky.androidide.tooling.api.models.BuildVariantInfo
+
+/**
+ * [RecyclerView] adapter for showing the list of Android modules and their selected build variant.
+ *
+ * @property items
+ * @author Akash Yadav
+ */
+class BuildVariantsAdapter(
+ private val items: List
+) : RecyclerView.Adapter() {
+
+
+ class ViewHolder(internal val binding: LayoutBuildVariantItemBinding) :
+ RecyclerView.ViewHolder(binding.root)
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val binding = LayoutBuildVariantItemBinding.inflate(LayoutInflater.from(parent.context), parent,
+ false)
+ return ViewHolder(binding)
+ }
+
+ override fun getItemCount(): Int {
+ return items.size
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val binding = holder.binding
+ val variantInfo = items[position]
+
+ binding.moduleName.text = variantInfo.modulePath
+ binding.variantName.setAdapter(
+ ArrayAdapter(binding.root.context, R.layout.support_simple_spinner_dropdown_item,
+ variantInfo.buildVariants
+ )
+ )
+
+ binding.variantName.listSelection = variantInfo.selectedVariantIndex
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/RecyclerViewFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/RecyclerViewFragment.kt
index bb7286481..aba447bf9 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/RecyclerViewFragment.kt
+++ b/app/src/main/java/com/itsaky/androidide/fragments/RecyclerViewFragment.kt
@@ -22,7 +22,6 @@ import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.RecyclerView.LayoutManager
-import com.itsaky.androidide.R
import com.itsaky.androidide.databinding.FragmentRecyclerviewBinding
/**
@@ -47,12 +46,19 @@ abstract class RecyclerViewFragment> :
return LinearLayoutManager(requireContext())
}
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
+ /**
+ * Sets up the recycler view in the fragment.
+ */
+ protected open fun onSetupRecyclerView() {
binding.root.apply {
layoutManager = onCreateLayoutManager()
adapter = unsavedAdapter ?: onCreateAdapter()
}
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ onSetupRecyclerView()
unsavedAdapter = null
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sidebar/BuildVariantsFragment.kt b/app/src/main/java/com/itsaky/androidide/fragments/sidebar/BuildVariantsFragment.kt
new file mode 100644
index 000000000..e6346a996
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/sidebar/BuildVariantsFragment.kt
@@ -0,0 +1,49 @@
+/*
+ * This file is part of AndroidIDE.
+ *
+ * AndroidIDE 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.
+ *
+ * AndroidIDE 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 AndroidIDE. If not, see .
+ */
+
+package com.itsaky.androidide.fragments.sidebar
+
+import android.os.Bundle
+import android.view.View
+import androidx.fragment.app.viewModels
+import androidx.recyclerview.widget.RecyclerView
+import com.itsaky.androidide.adapters.BuildVariantsAdapter
+import com.itsaky.androidide.fragments.RecyclerViewFragment
+import com.itsaky.androidide.viewmodel.EditorViewModel
+
+/**
+ * A fragment to show the list of Android modules and its build variants.
+ *
+ * @author Akash Yadav
+ */
+class BuildVariantsFragment : RecyclerViewFragment() {
+
+ private val viewModel by viewModels(ownerProducer = { requireActivity() })
+
+ override fun onCreateAdapter(): RecyclerView.Adapter<*> {
+ return BuildVariantsAdapter(viewModel.buildVariants)
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ viewModel._buildVariants.observe(viewLifecycleOwner) {
+
+ // Setup the recyclerview each time build variants list is updated
+ onSetupRecyclerView()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/utils/EditorSidebarActions.kt b/app/src/main/java/com/itsaky/androidide/utils/EditorSidebarActions.kt
index ca44da911..1d1649202 100644
--- a/app/src/main/java/com/itsaky/androidide/utils/EditorSidebarActions.kt
+++ b/app/src/main/java/com/itsaky/androidide/utils/EditorSidebarActions.kt
@@ -40,10 +40,12 @@ import com.itsaky.androidide.actions.ActionsRegistry
import com.itsaky.androidide.actions.FillMenuParams
import com.itsaky.androidide.actions.SidebarActionItem
import com.itsaky.androidide.actions.internal.DefaultActionsRegistry
+import com.itsaky.androidide.actions.sidebar.BuildVariantsSidebarAction
import com.itsaky.androidide.actions.sidebar.CloseProjectSidebarAction
import com.itsaky.androidide.actions.sidebar.FileTreeSidebarAction
import com.itsaky.androidide.actions.sidebar.PreferencesSidebarAction
import com.itsaky.androidide.actions.sidebar.TerminalSidebarAction
+import com.itsaky.androidide.fragments.sidebar.BuildVariantsFragment
import com.itsaky.androidide.fragments.sidebar.EditorSidebarFragment
import java.lang.ref.WeakReference
@@ -60,7 +62,10 @@ internal object EditorSidebarActions {
fun registerActions(context: Context) {
val registry = ActionsRegistry.getInstance()
var order = -1
+
+ @Suppress("KotlinConstantConditions")
registry.registerAction(FileTreeSidebarAction(context, ++order))
+ registry.registerAction(BuildVariantsSidebarAction(context, ++order))
registry.registerAction(TerminalSidebarAction(context, ++order))
registry.registerAction(PreferencesSidebarAction(context, ++order))
registry.registerAction(CloseProjectSidebarAction(context, ++order))
@@ -88,6 +93,7 @@ internal object EditorSidebarActions {
val data = ActionData()
data.put(Context::class.java, context) // needed for inflating the menu
+ val titleRef = WeakReference(binding.title)
val params = FillMenuParams(data, ActionItem.Location.EDITOR_SIDEBAR,
rail.menu) { actionsRegistry, action, item, actionsData ->
@@ -104,18 +110,15 @@ internal object EditorSidebarActions {
controller.navigate(action.id, navOptions {
launchSingleTop = true
restoreState = true
-
- popUpTo(controller.graph.findStartDestination().id) {
- inclusive = false
- saveState = true
- }
})
// Return true only if the destination we've navigated to matches the MenuItem
val result = controller.currentDestination?.matchDestination(action.id) == true
if (result) {
item.isChecked = true
+ titleRef.get()?.text = item.title
}
+
result
} catch (e: IllegalArgumentException) {
false
@@ -147,36 +150,6 @@ internal object EditorSidebarActions {
destination(builder)
}
}
-
- val railRef = WeakReference(rail)
- val titleRef = WeakReference(binding.title)
- controller.addOnDestinationChangedListener(
- object : NavController.OnDestinationChangedListener {
- override fun onDestinationChanged(
- controller: NavController,
- destination: NavDestination,
- arguments: Bundle?
- ) {
- val railView = railRef.get()
- if (railView == null) {
- controller.removeOnDestinationChangedListener(this)
- return
- }
-
- railView.menu.forEach { item ->
- if (destination.matchDestination(item.itemId)) {
- item.isChecked = true
- titleRef.get()?.text = item.title
- }
- }
- }
- })
-
- // make sure the 'File tree' item is checked by default
- rail.menu.findItem(FileTreeSidebarAction.ID.hashCode())?.also {
- it.isChecked = true
- binding.title.text = it.title
- }
}
/**
@@ -188,15 +161,6 @@ internal object EditorSidebarActions {
internal fun NavDestination.matchDestination(route: String): Boolean =
hierarchy.any { it.route == route }
- /**
- * Determines whether the given `destId` matches the NavDestination. This handles
- * both the default case (the destination's id matches the given id) and the nested case where
- * the given id is a parent/grandparent/etc of the destination.
- */
- @JvmStatic
- internal fun NavDestination.matchDestination(@IdRes destId: Int): Boolean =
- hierarchy.any { it.id == destId }
-
@JvmStatic
internal fun ShapeAppearanceModel.roundedOnRight(cornerSize: Float = 28f): ShapeAppearanceModel {
return toBuilder().run {
diff --git a/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.kt b/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.kt
index f5b3b0be1..ab7705661 100644
--- a/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.kt
+++ b/app/src/main/java/com/itsaky/androidide/viewmodel/EditorViewModel.kt
@@ -27,6 +27,7 @@ import com.google.gson.GsonBuilder
import com.itsaky.androidide.models.OpenedFilesCache
import com.itsaky.androidide.projects.ProjectManager
import com.itsaky.androidide.tasks.executeAsync
+import com.itsaky.androidide.tooling.api.models.BuildVariantInfo
import com.itsaky.androidide.utils.Environment
import java.io.File
@@ -52,6 +53,8 @@ class EditorViewModel : ViewModel() {
*/
private val mCurrentFile = MutableLiveData?>(null)
+ internal val _buildVariants = MutableLiveData>(null)
+
var openedFilesCache: OpenedFilesCache?
get() = _openedFiles.value
set(value) {
@@ -100,6 +103,12 @@ class EditorViewModel : ViewModel() {
_startDrawerOpened.value = value
}
+ var buildVariants: List
+ get() = this._buildVariants.value ?: emptyList()
+ set(value) {
+ this._buildVariants.value = value
+ }
+
/**
* Add the given file to the list of opened files.
*
diff --git a/app/src/main/res/layout/layout_build_variant_item.xml b/app/src/main/res/layout/layout_build_variant_item.xml
new file mode 100644
index 000000000..c192c5fc6
--- /dev/null
+++ b/app/src/main/res/layout/layout_build_variant_item.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/src/main/res/values/strings.xml b/resources/src/main/res/values/strings.xml
index c319dcb7f..487780713 100644
--- a/resources/src/main/res/values/strings.xml
+++ b/resources/src/main/res/values/strings.xml
@@ -594,4 +594,5 @@
Failed to perform code action
Enable LogSender
When disabled, logs from applications won\'t be shown in AndroidIDE
+ Build variants
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sidebar/BulidVariantsFragment.kt b/subprojects/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/models/BuildVariantInfo.kt
similarity index 59%
rename from app/src/main/java/com/itsaky/androidide/fragments/sidebar/BulidVariantsFragment.kt
rename to subprojects/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/models/BuildVariantInfo.kt
index a46b7cd64..94e2fb98b 100644
--- a/app/src/main/java/com/itsaky/androidide/fragments/sidebar/BulidVariantsFragment.kt
+++ b/subprojects/tooling-api-model/src/main/java/com/itsaky/androidide/tooling/api/models/BuildVariantInfo.kt
@@ -15,15 +15,15 @@
* along with AndroidIDE. If not, see .
*/
-package com.itsaky.androidide.fragments.sidebar
-
-import com.itsaky.androidide.fragments.EmptyStateFragment
-import com.itsaky.androidide.fragments.RecyclerViewFragment
+package com.itsaky.androidide.tooling.api.models
/**
- * A fragment to show the list of modules and the selected build variants in the
+ * Information about the build variants of an Android module.
*
+ * @property modulePath The project path of the Android module project.
+ * @property buildVariants The build variants of the Android module project.
+ * @property selectedVariantIndex The index of the build variant in the [buildVariants] list which is currently selected.
* @author Akash Yadav
*/
-class BulidVariantsFragment {
-}
\ No newline at end of file
+data class BuildVariantInfo(val modulePath: String, val buildVariants: List,
+ val selectedVariantIndex: Int)