diff --git a/.github/actions/build-setup/action.yml b/.github/actions/build-setup/action.yml new file mode 100644 index 0000000..8913288 --- /dev/null +++ b/.github/actions/build-setup/action.yml @@ -0,0 +1,17 @@ +name: Build Setup +description: Sets up Java, Gradle and Android. + +runs: + using: composite + steps: + - name: Set up JDK + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 24 # Can't upgrade to 25 before Detekt 2.0 is out. + + - name: Setup Android SDK + uses: android-actions/setup-android@v3 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1cd88ca..3d7b057 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,15 +15,12 @@ jobs: timeout-minutes: 15 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: clean: ${{ github.ref == 'refs/heads/develop' }} - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: 17 + - name: Build setup + uses: ./.github/actions/build-setup - name: Compile run: ./gradlew assemble \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 652fcd8..d0ca837 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -7,13 +7,10 @@ jobs: runs-on: macos-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: 17 + - name: Build setup + uses: ./.github/actions/build-setup - name: Publish Library env: diff --git a/compose-action-menu/build.gradle.kts b/compose-action-menu/build.gradle.kts index bf67a62..1591776 100644 --- a/compose-action-menu/build.gradle.kts +++ b/compose-action-menu/build.gradle.kts @@ -1,4 +1,4 @@ -import com.vanniktech.maven.publish.SonatypeHost +import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl plugins { @@ -7,13 +7,14 @@ plugins { alias(libs.plugins.compose.multiplatform) alias(libs.plugins.compose.compiler) alias(libs.plugins.maven.publish) + signing } group = "nl.jacobras" version = "3.1.0" mavenPublishing { - publishToMavenCentral(SonatypeHost.S01, true) + publishToMavenCentral() signAllPublications() pom { @@ -71,26 +72,30 @@ kotlin { wasmJs { browser() } sourceSets { - val commonMain by getting { - dependencies { - implementation(libs.compose.foundation) - implementation(libs.compose.icons) - implementation(libs.compose.material3) - implementation(libs.compose.ui) - } + commonMain.dependencies { + implementation(libs.compose.foundation) + implementation(libs.compose.icons) + implementation(libs.compose.material3) + implementation(libs.compose.ui) + implementation(libs.compose.uiToolingPreview) } - val androidMain by getting { + @OptIn(ExperimentalKotlinGradlePluginApi::class) + invokeWhenCreated("androidDebug") { dependencies { - implementation(compose.uiTooling) + implementation(libs.compose.uiTooling) } } } - - jvmToolchain(17) } // From https://github.com/gradle/gradle/issues/26091#issuecomment-1722947958 tasks.withType().configureEach { val signingTasks = tasks.withType() mustRunAfter(signingTasks) +} + +signing { + setRequired { + !gradle.taskGraph.allTasks.any { it is PublishToMavenLocal } + } } \ No newline at end of file diff --git a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/IconActionItemPreviews.kt b/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/IconActionItemPreviews.kt deleted file mode 100644 index 358ba25..0000000 --- a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/IconActionItemPreviews.kt +++ /dev/null @@ -1,92 +0,0 @@ -package nl.jacobras.composeactionmenu - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable - -@PreviewUiComponent -@Composable -private fun RegularIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun BlueIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun DisabledIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - enabled = false, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun TextIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = null, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun BlueTextIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = null, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun DisabledTextIconActionPreview() { - IconActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = null, - enabled = false, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} \ No newline at end of file diff --git a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItemPreviews.kt b/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItemPreviews.kt deleted file mode 100644 index c7734e3..0000000 --- a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItemPreviews.kt +++ /dev/null @@ -1,93 +0,0 @@ -package nl.jacobras.composeactionmenu - -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Search -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable - -@PreviewUiComponent -@Composable -private fun RegularOverflowActionPreview() { - OverflowActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun RegularOverflowActionWithoutIconPreview() { - OverflowActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = null, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun DisabledOverflowActionWithoutIconPreview() { - OverflowActionItem( - item = RegularActionItem( - key = "search", - title = "OK", - iconVector = null, - enabled = false, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun CheckableOverflowActionPreview() { - OverflowActionItem( - item = CheckableActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - isChecked = true, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun RadioOverflowActionPreview() { - OverflowActionItem( - item = RadioActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - isSelected = true, - onClick = {} - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} - -@PreviewUiComponent -@Composable -private fun GroupOverflowActionPreview() { - OverflowActionItem( - item = GroupActionItem( - key = "search", - title = "OK", - iconVector = Icons.Filled.Search, - childOptions = emptyList() - ), - contentColor = MaterialTheme.colorScheme.onSurface - ) -} \ No newline at end of file diff --git a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/ActionMenu.kt b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/ActionMenu.kt index 9108f4f..9ec5a97 100644 --- a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/ActionMenu.kt +++ b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/ActionMenu.kt @@ -102,7 +102,8 @@ fun ActionMenu( modifier = Modifier.testTag("ActionMenu#${item.key}"), hideTopMenu = { showOverflowMenu = false }, showSubMenu = { subMenuContent = it }, - hideSubMenu = { subMenuContent = emptyList() } + hideSubMenu = { subMenuContent = emptyList() }, + addPaddingIfNoIcon = content.any { it.icon != null || it.iconVector != null } ) } } diff --git a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/IconActionItem.kt b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/IconActionItem.kt index 56ff50e..a180f9f 100644 --- a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/IconActionItem.kt +++ b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/IconActionItem.kt @@ -1,7 +1,10 @@ package nl.jacobras.composeactionmenu +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -9,6 +12,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.rememberVectorPainter +/** + * An action item that shows an icon (or text when no icon is provided) for use in a toolbar. + */ @Composable internal fun IconActionItem( item: ActionItem, @@ -55,4 +61,90 @@ internal fun IconActionItem( Text(text = title, color = contentColor) } } +} + +@PreviewUiComponent +@Composable +private fun RegularIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) +} + +@PreviewUiComponent +@Composable +private fun BlueIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) +} + +@PreviewUiComponent +@Composable +private fun DisabledIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + enabled = false, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) +} + +@PreviewUiComponent +@Composable +private fun TextIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = null, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) +} + +@PreviewUiComponent +@Composable +private fun BlueTextIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = null, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) +} + +@PreviewUiComponent +@Composable +private fun DisabledTextIconActionPreview() { + IconActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = null, + enabled = false, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface + ) } \ No newline at end of file diff --git a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItem.kt b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItem.kt index 6066658..133e53f 100644 --- a/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItem.kt +++ b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/OverflowActionItem.kt @@ -1,5 +1,6 @@ package nl.jacobras.composeactionmenu +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -7,9 +8,11 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight +import androidx.compose.material.icons.filled.Search import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.RadioButton import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -20,10 +23,14 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +/** + * An action item for use in the overflow menu. + */ @Composable internal fun OverflowActionItem( item: ActionItem, contentColor: Color, + addPaddingIfNoIcon: Boolean, modifier: Modifier = Modifier, hideTopMenu: () -> Unit = {}, showSubMenu: (items: List) -> Unit = {}, @@ -68,16 +75,19 @@ internal fun OverflowActionItem( item.icon != null -> item.icon else -> null } + val textAlpha = if (item.enabled) 1.0f else 0.5f if (iconPainter != null) { + Spacer(modifier = Modifier.width(2.dp)) Icon( painter = iconPainter, contentDescription = null, - tint = contentColor + tint = contentColor.copy(textAlpha) ) + Spacer(modifier = Modifier.width(6.dp)) + } else if (addPaddingIfNoIcon) { + Spacer(modifier = Modifier.width(32.dp)) } - Spacer(modifier = Modifier.width(8.dp)) - val textAlpha = if (item.enabled) 1.0f else 0.5f Text( modifier = Modifier .weight(1f) @@ -113,4 +123,140 @@ internal fun OverflowActionItem( } } ) +} + +@PreviewUiComponent +@Composable +private fun RegularOverflowActionItemPreview() { + OverflowActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun RegularOverflowActionItemWithoutIconPreview() { + OverflowActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = null, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun OverflowActionItemWithPadding() { + Column { + OverflowActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = true + ) + OverflowActionItem( + item = RegularActionItem( + key = "somethingElse", + title = "Something else", + iconVector = null, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = true + ) + } +} + +@PreviewUiComponent +@Composable +private fun DisabledOverflowActionItemWithoutIconPreview() { + OverflowActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = null, + enabled = false, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun DisabledOverflowActionItemWithIconPreview() { + OverflowActionItem( + item = RegularActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + enabled = false, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun CheckableOverflowActionItemPreview() { + OverflowActionItem( + item = CheckableActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + isChecked = true, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun RadioOverflowActionItemPreview() { + OverflowActionItem( + item = RadioActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + isSelected = true, + onClick = {} + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) +} + +@PreviewUiComponent +@Composable +private fun GroupOverflowActionItemPreview() { + OverflowActionItem( + item = GroupActionItem( + key = "search", + title = "OK", + iconVector = Icons.Filled.Search, + childOptions = emptyList() + ), + contentColor = MaterialTheme.colorScheme.onSurface, + addPaddingIfNoIcon = false + ) } \ No newline at end of file diff --git a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt similarity index 83% rename from compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt rename to compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt index 57f511e..f18ad75 100644 --- a/compose-action-menu/src/androidMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt +++ b/compose-action-menu/src/commonMain/kotlin/nl/jacobras/composeactionmenu/PreviewAnnotations.kt @@ -1,7 +1,7 @@ package nl.jacobras.composeactionmenu -import android.content.res.Configuration.UI_MODE_NIGHT_YES -import android.content.res.Configuration.UI_MODE_TYPE_NORMAL +import androidx.compose.ui.tooling.preview.AndroidUiModes.UI_MODE_NIGHT_YES +import androidx.compose.ui.tooling.preview.AndroidUiModes.UI_MODE_TYPE_NORMAL import androidx.compose.ui.tooling.preview.Preview /** diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 852a6e8..4a0f435 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,6 +13,7 @@ compose-material3 = { module = "org.jetbrains.compose.material3:material3", vers compose-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose" } compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose" } compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose" } +compose-uiTooling = { module = "org.jetbrains.compose.ui:ui-tooling", version.ref = "compose" } compose-uiToolingPreview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose" } [bundles] @@ -22,4 +23,4 @@ android-application = { id = "com.android.application", version.ref = "agp" } android-library = { id = "com.android.library", version.ref = "agp" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "compose" } -maven-publish = { id = "com.vanniktech.maven.publish", version = "0.30.0" } \ No newline at end of file +maven-publish = { id = "com.vanniktech.maven.publish", version = "0.36.0" } \ No newline at end of file diff --git a/sample-app/src/main/kotlin/nl/jacobras/composeactionmenu/sample/MainActivity.kt b/sample-app/src/main/kotlin/nl/jacobras/composeactionmenu/sample/MainActivity.kt index 9e35767..275b650 100644 --- a/sample-app/src/main/kotlin/nl/jacobras/composeactionmenu/sample/MainActivity.kt +++ b/sample-app/src/main/kotlin/nl/jacobras/composeactionmenu/sample/MainActivity.kt @@ -9,10 +9,11 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccountBox +import androidx.compose.material.icons.filled.Create import androidx.compose.material.icons.filled.Email import androidx.compose.material.icons.filled.Home import androidx.compose.material.icons.filled.Info -import androidx.compose.material.icons.filled.LocationOn import androidx.compose.material.icons.filled.Person import androidx.compose.material.icons.filled.Phone import androidx.compose.material3.ExperimentalMaterial3Api @@ -41,7 +42,7 @@ class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { - val useLocation = remember { mutableStateOf(false) } + val sampleCheckbox = remember { mutableStateOf(false) } val contactMethod = remember { mutableIntStateOf(2) } val person = remember { mutableIntStateOf(1) } @@ -50,7 +51,7 @@ class MainActivity : ComponentActivity() { topBar = { TopAppBar( title = { Text(text = stringResource(id = R.string.app_name)) }, - actions = { ActionMenu(items = buildToolbarActions(useLocation, contactMethod, person)) } + actions = { ActionMenu(items = buildToolbarActions(sampleCheckbox, contactMethod, person)) } ) }, containerColor = MaterialTheme.colorScheme.surfaceContainer @@ -62,7 +63,7 @@ class MainActivity : ComponentActivity() { ) { Text("Welcome to the sample app! Try out the menu options above.") Spacer(modifier = Modifier.height(8.dp)) - Text("Use location (just some example text): ${useLocation.value}") + Text("Sample checkbox: ${sampleCheckbox.value}") Spacer(modifier = Modifier.height(8.dp)) Text("Person selected: #${person.intValue}") Spacer(modifier = Modifier.height(8.dp)) @@ -112,8 +113,8 @@ class MainActivity : ComponentActivity() { ), CheckableActionItem( key = "useLocation", - title = stringResource(R.string.use_location), - iconVector = Icons.Default.LocationOn, + title = stringResource(R.string.sample_checkbox), + iconVector = Icons.Default.AccountBox, isChecked = useLocationState.value, onClick = { useLocationState.value = !useLocationState.value } ), @@ -147,6 +148,7 @@ class MainActivity : ComponentActivity() { RegularActionItem( key = "disabledExample", title = stringResource(R.string.disabled_example), + iconVector = Icons.Default.Create, showAsAction = ShowAsActionMode.NEVER, enabled = false, onClick = ::onActionItemClick diff --git a/sample-app/src/main/res/values/strings.xml b/sample-app/src/main/res/values/strings.xml index 65f2598..83d7032 100644 --- a/sample-app/src/main/res/values/strings.xml +++ b/sample-app/src/main/res/values/strings.xml @@ -9,7 +9,7 @@ Phone E-mail Post - Use location + Sample checkbox Settings Disabled example \ No newline at end of file