diff --git a/tools/templates/RiotXFeature/globals.xml.ftl b/tools/templates/RiotXFeature/globals.xml.ftl
new file mode 100644
index 0000000000..7cafd80483
--- /dev/null
+++ b/tools/templates/RiotXFeature/globals.xml.ftl
@@ -0,0 +1,6 @@
+
+
+ <#include "root://activities/common/common_globals.xml.ftl" />
+
+
+
diff --git a/tools/templates/RiotXFeature/recipe.xml.ftl b/tools/templates/RiotXFeature/recipe.xml.ftl
new file mode 100644
index 0000000000..88160fd0f3
--- /dev/null
+++ b/tools/templates/RiotXFeature/recipe.xml.ftl
@@ -0,0 +1,37 @@
+
+<#import "root://activities/common/kotlin_macros.ftl" as kt>
+
+
+
+
+
+ <#if createActivity>
+
+
+ #if>
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <#if createViewEvents>
+
+
+ #if>
+
+
diff --git a/tools/templates/RiotXFeature/root/AndroidManifest.xml.ftl b/tools/templates/RiotXFeature/root/AndroidManifest.xml.ftl
new file mode 100644
index 0000000000..97c85c4160
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/AndroidManifest.xml.ftl
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tools/templates/RiotXFeature/root/res/layout/fragment.xml.ftl b/tools/templates/RiotXFeature/root/res/layout/fragment.xml.ftl
new file mode 100644
index 0000000000..539c40f3f9
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/res/layout/fragment.xml.ftl
@@ -0,0 +1,20 @@
+
+
+
+
+
+
diff --git a/tools/templates/RiotXFeature/root/src/app_package/Action.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/Action.kt.ftl
new file mode 100644
index 0000000000..7492907e6c
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/Action.kt.ftl
@@ -0,0 +1,5 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import im.vector.riotx.core.platform.VectorViewModelAction
+
+sealed class ${actionClass}: VectorViewModelAction
\ No newline at end of file
diff --git a/tools/templates/RiotXFeature/root/src/app_package/Activity.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/Activity.kt.ftl
new file mode 100644
index 0000000000..fdac319482
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/Activity.kt.ftl
@@ -0,0 +1,49 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import android.content.Context
+import android.content.Intent
+import androidx.appcompat.widget.Toolbar
+import im.vector.riotx.R
+import im.vector.riotx.core.extensions.addFragment
+import im.vector.riotx.core.platform.ToolbarConfigurable
+import im.vector.riotx.core.platform.VectorBaseActivity
+
+//TODO: add this activity to manifest
+class ${activityClass} : VectorBaseActivity(), ToolbarConfigurable {
+
+ companion object {
+
+ <#if createFragmentArgs>
+ private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS"
+
+ fun newIntent(context: Context, args: ${fragmentArgsClass}): Intent {
+ return Intent(context, ${activityClass}::class.java).apply {
+ putExtra(EXTRA_FRAGMENT_ARGS, args)
+ }
+ }
+ <#else>
+ fun newIntent(context: Context): Intent {
+ return Intent(context, ${activityClass}::class.java)
+ }
+ #if>
+ }
+
+ override fun getLayoutRes() = R.layout.activity_simple
+
+ override fun initUiAndData() {
+ if (isFirstCreation()) {
+ <#if createFragmentArgs>
+ val fragmentArgs: ${fragmentArgsClass} = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS)
+ ?: return
+ addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java, fragmentArgs)
+ <#else>
+ addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java)
+ #if>
+ }
+ }
+
+ override fun configure(toolbar: Toolbar) {
+ configureToolbar(toolbar)
+ }
+
+}
diff --git a/tools/templates/RiotXFeature/root/src/app_package/Fragment.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/Fragment.kt.ftl
new file mode 100644
index 0000000000..53dd3a52dc
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/Fragment.kt.ftl
@@ -0,0 +1,47 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import android.os.Bundle
+<#if createFragmentArgs>
+import android.os.Parcelable
+import kotlinx.android.parcel.Parcelize
+import com.airbnb.mvrx.args
+#if>
+import android.view.View
+import com.airbnb.mvrx.fragmentViewModel
+import com.airbnb.mvrx.withState
+import im.vector.riotx.R
+import im.vector.riotx.core.platform.VectorBaseFragment
+import javax.inject.Inject
+
+<#if createFragmentArgs>
+@Parcelize
+data class ${fragmentArgsClass}() : Parcelable
+#if>
+
+//TODO: add this fragment into FragmentModule
+class ${fragmentClass} @Inject constructor(
+ val viewModelFactory: ${viewModelClass}.Factory
+) : VectorBaseFragment() {
+
+ <#if createFragmentArgs>
+ private val fragmentArgs: ${fragmentArgsClass} by args()
+ #if>
+ private val viewModel: ${viewModelClass} by fragmentViewModel()
+
+ override fun getLayoutResId() = R.layout.${fragmentLayout}
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ // Initialize your view, subscribe to viewModel...
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ // Clear your view, unsubscribe...
+ }
+
+ override fun invalidate() = withState(viewModel) { state ->
+ //TODO
+ }
+
+}
diff --git a/tools/templates/RiotXFeature/root/src/app_package/ViewEvents.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/ViewEvents.kt.ftl
new file mode 100644
index 0000000000..4d7d2ee450
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/ViewEvents.kt.ftl
@@ -0,0 +1,5 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import im.vector.riotx.core.platform.VectorViewEvents
+
+sealed class ${viewEventsClass} : VectorViewEvents
\ No newline at end of file
diff --git a/tools/templates/RiotXFeature/root/src/app_package/ViewModel.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/ViewModel.kt.ftl
new file mode 100644
index 0000000000..1e87714655
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/ViewModel.kt.ftl
@@ -0,0 +1,39 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import com.airbnb.mvrx.FragmentViewModelContext
+import com.airbnb.mvrx.MvRxViewModelFactory
+import com.airbnb.mvrx.ViewModelContext
+import com.squareup.inject.assisted.Assisted
+import com.squareup.inject.assisted.AssistedInject
+import im.vector.riotx.core.platform.VectorViewModel
+
+<#if createViewEvents>
+<#else>
+import im.vector.riotx.core.platform.EmptyViewEvents
+#if>
+
+class ${viewModelClass} @AssistedInject constructor(@Assisted initialState: ${viewStateClass})
+ <#if createViewEvents>
+ : VectorViewModel<${viewStateClass}, ${actionClass}, ${viewEventsClass}>(initialState) {
+ <#else>
+ : VectorViewModel<${viewStateClass}, ${actionClass}, EmptyViewEvents>(initialState) {
+ #if>
+ @AssistedInject.Factory
+ interface Factory {
+ fun create(initialState: ${viewStateClass}): ${viewModelClass}
+ }
+
+ companion object : MvRxViewModelFactory<${viewModelClass}, ${viewStateClass}> {
+
+ @JvmStatic
+ override fun create(viewModelContext: ViewModelContext, state: ${viewStateClass}): ${viewModelClass}? {
+ val fragment: ${fragmentClass} = (viewModelContext as FragmentViewModelContext).fragment()
+ return fragment.viewModelFactory.create(state)
+ }
+ }
+
+ override fun handle(action: ${actionClass}) {
+ //TODO
+ }
+
+}
diff --git a/tools/templates/RiotXFeature/root/src/app_package/ViewState.kt.ftl b/tools/templates/RiotXFeature/root/src/app_package/ViewState.kt.ftl
new file mode 100644
index 0000000000..55e1f5f549
--- /dev/null
+++ b/tools/templates/RiotXFeature/root/src/app_package/ViewState.kt.ftl
@@ -0,0 +1,5 @@
+package ${escapeKotlinIdentifiers(packageName)}
+
+import com.airbnb.mvrx.MvRxState
+
+data class ${viewStateClass}() : MvRxState
\ No newline at end of file
diff --git a/tools/templates/RiotXFeature/template.xml b/tools/templates/RiotXFeature/template.xml
new file mode 100644
index 0000000000..33d2edfc70
--- /dev/null
+++ b/tools/templates/RiotXFeature/template.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+