diff --git a/tools/templates/file_templates.zip b/tools/templates/file_templates.zip deleted file mode 100644 index 7352ac3074..0000000000 Binary files a/tools/templates/file_templates.zip and /dev/null differ diff --git a/tools/templates/files/IntelliJ IDEA Global Settings b/tools/templates/files/IntelliJ IDEA Global Settings new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tools/templates/files/fileTemplates/Template Module Feature Build Gradle API.kts b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle API.kts new file mode 100644 index 0000000000..5c72896315 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle API.kts @@ -0,0 +1,11 @@ +plugins { + id("io.element.android-library") +} + +android { + namespace = "io.element.android.features.${MODULE_NAME}.api" +} + +dependencies { + implementation(projects.libraries.architecture) +} diff --git a/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts new file mode 100644 index 0000000000..f38e5f8a6e --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Module Feature Build Gradle Impl.kts @@ -0,0 +1,36 @@ +// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed +@Suppress("DSL_SCOPE_VIOLATION") +plugins { + id("io.element.android-compose-library") + alias(libs.plugins.anvil) + alias(libs.plugins.ksp) + id("kotlin-parcelize") +} + +android { + namespace = "io.element.android.features.${MODULE_NAME}.impl" +} + +anvil { + generateDaggerFactories.set(true) +} + +dependencies { + implementation(projects.anvilannotations) + anvil(projects.anvilcodegen) + api(projects.features.${MODULE_NAME}.api) + implementation(projects.libraries.core) + implementation(projects.libraries.architecture) + implementation(projects.libraries.matrix.api) + implementation(projects.libraries.matrixui) + implementation(projects.libraries.designsystem) + + testImplementation(libs.test.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(projects.libraries.matrix.test) + + ksp(libs.showkase.processor) +} diff --git a/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt b/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt new file mode 100644 index 0000000000..54ede7ad0d --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Module Feature Entry Point API.kt @@ -0,0 +1,21 @@ +package io.element.android.features.${MODULE_NAME}.api + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint + +interface ${FEATURE_NAME}EntryPoint : FeatureEntryPoint { + + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder + + interface NodeBuilder { + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + interface Callback : Plugin { + // Add your callbacks + } +} + diff --git a/tools/templates/files/fileTemplates/Template Module Feature Entry Point Flow Impl.kt b/tools/templates/files/fileTemplates/Template Module Feature Entry Point Flow Impl.kt new file mode 100644 index 0000000000..adfd142ae5 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Module Feature Entry Point Flow Impl.kt @@ -0,0 +1,30 @@ +package io.element.android.features.${MODULE_NAME}.impl + +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.squareup.anvil.annotations.ContributesBinding +import io.element.android.features.${MODULE_NAME}.api.${FEATURE_NAME}EntryPoint +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import javax.inject.Inject + +@ContributesBinding(AppScope::class) +class Default${FEATURE_NAME}EntryPoint @Inject constructor() : ${FEATURE_NAME}EntryPoint { + + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): ${FEATURE_NAME}EntryPoint.NodeBuilder { + val plugins = ArrayList() + + return object : ${FEATURE_NAME}EntryPoint.NodeBuilder { + + override fun callback(callback: ${FEATURE_NAME}EntryPoint.Callback): ${FEATURE_NAME}EntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode<${FEATURE_NAME}FlowNode>(buildContext, plugins) + } + } + } +} diff --git a/tools/templates/files/fileTemplates/Template Module Feature Node Flow Impl.kt b/tools/templates/files/fileTemplates/Template Module Feature Node Flow Impl.kt new file mode 100644 index 0000000000..299239f142 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Module Feature Node Flow Impl.kt @@ -0,0 +1,57 @@ +package io.element.android.features.${MODULE_NAME}.impl + +import android.os.Parcelable +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.composable.Children +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.push +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.architecture.BackstackNode +import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler +import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.di.AppScope +import kotlinx.parcelize.Parcelize + +// CHANGE THE SCOPE +@ContributesNode(AppScope::class) +class ${FEATURE_NAME}FlowNode @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, +) : BackstackNode<${FEATURE_NAME}FlowNode.NavTarget>( + backstack = BackStack( + initialElement = NavTarget.Root, + savedStateMap = buildContext.savedStateMap, + ), + buildContext = buildContext, + plugins = plugins, +) { + + sealed interface NavTarget : Parcelable { + @Parcelize + object Root : NavTarget + } + + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { + return when (navTarget) { + NavTarget.Root -> { + //Give your root node or completely delete this FlowNode if you have only one node. + createNode<>(buildContext) + } + } + } + + @Composable + override fun View(modifier: Modifier) { + Children( + navModel = backstack, + modifier = modifier, + transitionHandler = rememberDefaultTransitionHandler(), + ) + } +} \ No newline at end of file diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt new file mode 100644 index 0000000000..a095220199 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt @@ -0,0 +1,22 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +import androidx.compose.runtime.Composable +import io.element.android.libraries.architecture.Presenter +import javax.inject.Inject + +class ${NAME}Presenter @Inject constructor() : Presenter<${NAME}State> { + + @Composable + override fun present(): ${NAME}State { + + fun handleEvents(event: ${NAME}Events) { + when (event) { + ${NAME}Events.MyEvent -> Unit + } + } + + return ${NAME}State( + eventSink = ::handleEvents + ) + } +} \ No newline at end of file diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.0.kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.0.kt new file mode 100644 index 0000000000..26372fc970 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.0.kt @@ -0,0 +1,15 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +import androidx.compose.ui.tooling.preview.PreviewParameterProvider + +open class ${NAME}StateProvider : PreviewParameterProvider<${NAME}State> { + override val values: Sequence<${NAME}State> + get() = sequenceOf( + a${NAME}State(), + // Add other states here + ) +} + +fun a${NAME}State() = ${NAME}State( + eventSink = {} +) diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.1.kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.1.kt new file mode 100644 index 0000000000..9c3f7842b9 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.1.kt @@ -0,0 +1,29 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import io.element.android.anvilannotations.ContributesNode +import io.element.android.libraries.di.AppScope + +// CHANGE THE SCOPE +@ContributesNode(AppScope::class) +class ${NAME}Node @AssistedInject constructor( + @Assisted buildContext: BuildContext, + @Assisted plugins: List, + private val presenter: ${NAME}Presenter, +) : Node(buildContext, plugins = plugins) { + + @Composable + override fun View(modifier: Modifier) { + val state = presenter.present() + ${NAME}View( + state = state, + modifier = modifier + ) + } +} \ No newline at end of file diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.2.kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.2.kt new file mode 100644 index 0000000000..b19f3e728e --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.2.kt @@ -0,0 +1,42 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +import androidx.compose.foundation.layout.Box +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import io.element.android.libraries.designsystem.preview.ElementPreviewDark +import io.element.android.libraries.designsystem.preview.ElementPreviewLight +import io.element.android.libraries.designsystem.theme.components.Text + +@Composable +fun ${NAME}View( + state: ${NAME}State, + modifier: Modifier = Modifier, +) { + Box(modifier, contentAlignment = Alignment.Center) { + Text( + "${NAME} feature view", + color = MaterialTheme.colorScheme.primary, + ) + } +} + +@Preview +@Composable +fun ${NAME}ViewLightPreview(@PreviewParameter(${NAME}StateProvider::class) state: ${NAME}State) = + ElementPreviewLight { ContentToPreview(state) } + +@Preview +@Composable +fun ${NAME}ViewDarkPreview(@PreviewParameter(${NAME}StateProvider::class) state: ${NAME}State) = + ElementPreviewDark { ContentToPreview(state) } + +@Composable +private fun ContentToPreview(state: ${NAME}State) { + ${NAME}View( + state = state, + ) +} \ No newline at end of file diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.3.kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.3.kt new file mode 100644 index 0000000000..3fcdd7f219 --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.3.kt @@ -0,0 +1,7 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +// TODO add your ui models. Remove the eventSink if you don't have events. +// Do not use default value, so no member get forgotten in the presenters. +data class ${NAME}State( + val eventSink: (${NAME}Events) -> Unit +) diff --git a/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.4.kt b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.4.kt new file mode 100644 index 0000000000..6ce6d089ee --- /dev/null +++ b/tools/templates/files/fileTemplates/Template Presentation Classes .kt.child.4.kt @@ -0,0 +1,6 @@ +#if (${PACKAGE_NAME} && ${PACKAGE_NAME} != "")package ${PACKAGE_NAME}#end + +// TODO Add your events or remove the file completely if no events +sealed interface ${NAME}Events { + object MyEvent: ${NAME}Events +} diff --git a/tools/templates/files/options/file.template.settings.xml b/tools/templates/files/options/file.template.settings.xml new file mode 100644 index 0000000000..d577903b92 --- /dev/null +++ b/tools/templates/files/options/file.template.settings.xml @@ -0,0 +1,18 @@ + + + +