diff --git a/E13RoomShoppingList/.idea/inspectionProfiles/Project_Default.xml b/E13RoomShoppingList/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000000000000000000000000000000000..103e00cbeb59714b53faaf27107bf190ecf0aa9e --- /dev/null +++ b/E13RoomShoppingList/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,32 @@ +<component name="InspectionProjectProfileManager"> + <profile version="1.0"> + <option name="myName" value="Project Default" /> + <inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + <inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true"> + <option name="composableFile" value="true" /> + </inspection_tool> + </profile> +</component> \ No newline at end of file diff --git a/E13RoomShoppingList/app/build.gradle.kts b/E13RoomShoppingList/app/build.gradle.kts index 357888dc2309795b7493b68c4c1471b4423a5042..e39dc596e4e1c6e9f4bfb6095787b3e05729de14 100644 --- a/E13RoomShoppingList/app/build.gradle.kts +++ b/E13RoomShoppingList/app/build.gradle.kts @@ -76,4 +76,7 @@ dependencies { // Material compose 3 implementation("androidx.compose.material3:material3:1.1.2") implementation("androidx.compose.material3:material3-window-size-class:1.1.2") + + // Google ads + implementation("com.google.android.gms:play-services-ads:22.6.0") } \ No newline at end of file diff --git a/E13RoomShoppingList/app/src/main/AndroidManifest.xml b/E13RoomShoppingList/app/src/main/AndroidManifest.xml index 46ed83d0551248cc5bd0708533a271c3d1552972..b6494408a4978c20b32a7d617026aa9def080892 100644 --- a/E13RoomShoppingList/app/src/main/AndroidManifest.xml +++ b/E13RoomShoppingList/app/src/main/AndroidManifest.xml @@ -23,6 +23,23 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + + <!-- Admob --> + <!-- Sample Ad Manager app ID: ca-app-pub-3940256099942544~3347511713 --> + <meta-data + android:name="com.google.android.gms.ads.APPLICATION_ID" + android:value="ca-app-pub-3940256099942544~3347511713"/> + <!-- Here are demo ad units that point to specific test creatives for each format:--> + <!-- Ad format Sample ad unit ID--> + <!-- App Open ca-app-pub-3940256099942544/9257395921--> + <!-- Adaptive Banner ca-app-pub-3940256099942544/9214589741--> + <!-- Banner ca-app-pub-3940256099942544/6300978111--> + <!-- Interstitial ca-app-pub-3940256099942544/1033173712--> + <!-- Interstitial Video ca-app-pub-3940256099942544/8691691433--> + <!-- Rewarded ca-app-pub-3940256099942544/5224354917--> + <!-- Rewarded Interstitial ca-app-pub-3940256099942544/5354046379--> + <!-- Native Advanced ca-app-pub-3940256099942544/2247696110--> + <!-- Native Advanced Video ca-app-pub-3940256099942544/1044960115--> </application> </manifest> \ No newline at end of file diff --git a/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/AdmobAds.kt b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/AdmobAds.kt new file mode 100644 index 0000000000000000000000000000000000000000..d6065b2d7ceadd13e2e571d18f75a93ba936d3a6 --- /dev/null +++ b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/AdmobAds.kt @@ -0,0 +1,146 @@ +package com.example.e13roomshoppinglist + +import android.app.Activity +import android.content.Context +import android.content.ContextWrapper +import com.google.android.gms.ads.AdError +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.FullScreenContentCallback +import com.google.android.gms.ads.LoadAdError +import com.google.android.gms.ads.interstitial.InterstitialAd +import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback +import com.google.android.gms.ads.rewarded.RewardItem +import com.google.android.gms.ads.rewarded.RewardedAd +import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback + + +const val interstitialUnitId = "ca-app-pub-3940256099942544/1033173712" +const val rewardedUnitId = "ca-app-pub-3940256099942544/5224354917" +var mInterstitialAd: InterstitialAd? = null +var mRewardedAd: RewardedAd? = null + + +fun loadInterstitial( + context: Context, + onLoadedAd: () -> Unit = {}, + onFailedToLoadAd: () -> Unit = {} +) { + InterstitialAd.load( + context, + interstitialUnitId, //Change this with your own AdUnitID! + AdRequest.Builder().build(), + object : InterstitialAdLoadCallback() { + override fun onAdFailedToLoad(adError: LoadAdError) { + mInterstitialAd = null + onFailedToLoadAd() + } + + override fun onAdLoaded(interstitialAd: InterstitialAd) { + mInterstitialAd = interstitialAd + onLoadedAd() + } + } + ) +} + +fun loadRewarded( + context: Context, + onLoadedAd: () -> Unit = {}, + onFailedToLoadAd: () -> Unit = {} +) { + RewardedAd.load( + context, + rewardedUnitId, //Change this with your own AdUnitID! + AdRequest.Builder().build(), + object : RewardedAdLoadCallback() { + override fun onAdFailedToLoad(adError: LoadAdError) { + mRewardedAd = null + onFailedToLoadAd() + } + + override fun onAdLoaded(rewardedAd: RewardedAd) { + mRewardedAd = rewardedAd + onLoadedAd() + } + } + ) +} + + +fun showInterstitial( + context: Context, + onLoadedAd: () -> Unit = {}, + onShowingAd: () -> Unit = {}, + onAdDismissed: () -> Unit = {}, + onFailedToLoadAd: () -> Unit = {}, + onFailedToShowFullScreenAd: () -> Unit = {}, +) { + val activity = context.findActivity() + + if (mInterstitialAd != null && activity != null) { + mInterstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() { + override fun onAdFailedToShowFullScreenContent(e: AdError) { + mInterstitialAd = null + onFailedToShowFullScreenAd() + } + + override fun onAdDismissedFullScreenContent() { + mInterstitialAd = null + + loadInterstitial(context, onFailedToLoadAd, onLoadedAd) + onAdDismissed() + } + } + mInterstitialAd?.show(activity).also { + onShowingAd() + } + } +} + +fun showRewarded( + context: Context, + onLoadedAd: () -> Unit = {}, + onShowingAd: () -> Unit = {}, + onAdDismissed: () -> Unit = {}, + onUserEarnedRewardListener: (item: RewardItem) -> Unit = {}, + onFailedToLoadAd: () -> Unit = {}, + onFailedToShowFullScreenAd: () -> Unit = {}, +) { + val activity = context.findActivity() + if (mRewardedAd != null && activity != null) { + mRewardedAd?.fullScreenContentCallback = object : FullScreenContentCallback() { + override fun onAdFailedToShowFullScreenContent(e: AdError) { + mRewardedAd = null + onFailedToShowFullScreenAd() + } + + override fun onAdDismissedFullScreenContent() { + mRewardedAd = null + + loadRewarded(context, onFailedToLoadAd, onLoadedAd) + onAdDismissed() + } + } + mRewardedAd?.show(activity, onUserEarnedRewardListener).also { + onShowingAd() + } + } +} + + +fun removeInterstitial() { + mInterstitialAd?.fullScreenContentCallback = null + mInterstitialAd = null +} + +fun removeRewarded() { + mRewardedAd?.fullScreenContentCallback = null + mRewardedAd = null +} + + +fun Context.findActivity(): Activity? = when (this) { + is Activity -> this + is ContextWrapper -> baseContext.findActivity() + else -> null +} diff --git a/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/MainActivity.kt b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/MainActivity.kt index f6a2502e9ea3b7562714a8251232ebfb75552f5b..21765b3d7ce92c7f364aab5ce298f39724f3afe5 100644 --- a/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/MainActivity.kt +++ b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/MainActivity.kt @@ -1,14 +1,18 @@ package com.example.e13roomshoppinglist import android.annotation.SuppressLint +import android.content.Context import android.os.Bundle import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.viewModels +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -17,14 +21,21 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.viewinterop.AndroidView import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.room.Room import com.example.e13roomshoppinglist.ui.theme.E13RoomShoppingListTheme +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.AdSize +import com.google.android.gms.ads.AdView +import com.google.android.gms.ads.MobileAds +import com.google.android.gms.ads.RequestConfiguration import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch +import java.util.Collections class MainActivity : ComponentActivity() { private val db by lazy { @@ -42,10 +53,23 @@ class MainActivity : ComponentActivity() { } } + override fun onDestroy() { + removeInterstitial() + removeRewarded() + super.onDestroy() + } + @OptIn(DelicateCoroutinesApi::class) @SuppressLint("CoroutineCreationDuringComposition") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + // Load ads + MobileAds.initialize(this) + loadInterstitial(this.applicationContext) + loadRewarded(this.applicationContext) + + setContent { E13RoomShoppingListTheme { val state by viewModel.state.collectAsState() @@ -62,7 +86,6 @@ class MainActivity : ComponentActivity() { toast = Toast.makeText(ctx, msg, Toast.LENGTH_SHORT) toast?.show() } - Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background diff --git a/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/ShoppingListScreen.kt b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/ShoppingListScreen.kt index 43b113a8b9527e351366a8f56e3db872375ef515..b5b57c9e35924f24b10a3bd45bfeaeae3ffdc131 100644 --- a/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/ShoppingListScreen.kt +++ b/E13RoomShoppingList/app/src/main/java/com/example/e13roomshoppinglist/ShoppingListScreen.kt @@ -1,10 +1,11 @@ package com.example.e13roomshoppinglist +import android.content.Context +import android.util.Log import androidx.compose.animation.animateColorAsState import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.layout.Arrangement @@ -14,7 +15,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.sizeIn import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items @@ -24,10 +27,7 @@ import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete -import androidx.compose.material.icons.filled.Done import androidx.compose.material.icons.filled.Edit -import androidx.compose.material.icons.outlined.Delete -import androidx.compose.material.icons.outlined.Edit import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.DismissDirection @@ -46,48 +46,95 @@ import androidx.compose.material3.TextField import androidx.compose.material3.rememberDismissState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.compose.ui.viewinterop.AndroidView +import com.google.android.gms.ads.AdRequest +import com.google.android.gms.ads.AdSize +import com.google.android.gms.ads.AdView +import kotlin.random.Random @OptIn(ExperimentalMaterial3Api::class) @Composable fun ShoppingListScreen( - state: ShoppingListState, - onEvent: (ShoppingListEvent) -> Unit, - onShowToast: (String) -> Unit? + state: ShoppingListState, onEvent: (ShoppingListEvent) -> Unit, onShowToast: (String) -> Unit? ) { - Scaffold( - floatingActionButton = { - FloatingActionButton(onClick = { - onEvent(ShoppingListEvent.OpenAddingNewShoppingListItemDialog) - }) { - Icon( - imageVector = Icons.Default.Add, - contentDescription = "Add new shopping list item" - ) - } - }, - modifier = Modifier.padding(16.dp) - ) { padding -> + var shouldShowInterstitialAd by rememberSaveable { + mutableStateOf(false) + } + var shouldShowRewardAd by rememberSaveable { + mutableStateOf(false) + } + + Scaffold(modifier = Modifier.padding(16.dp), floatingActionButton = { + FloatingActionButton(modifier = Modifier + .offset(x = 16.dp, y = 69.dp) + .sizeIn(maxHeight = 50.dp, maxWidth = 40.dp), onClick = { + onEvent(ShoppingListEvent.OpenAddingNewShoppingListItemDialog) + + val randInt = (1..2).random() + if (randInt==1) shouldShowInterstitialAd = true + else shouldShowRewardAd = true + }) { + Icon( + imageVector = Icons.Default.Add, + contentDescription = "Add new shopping list item" + ) + } + }, bottomBar = { + AdMobBannersAd( + modifier = Modifier + .height(54.dp) + .background(Color.White) + .padding(top = 4.dp), + contentAlignment = Alignment.TopStart + ) + }) { padding -> if (state.isAddingNewShoppingListItem || state.isEditingShoppingListItem) { AddShoppingListItemDialog(state = state, onEvent = onEvent, onShowToast = onShowToast) } - Column { + val ctx = LocalContext.current + if (shouldShowRewardAd) { + showRewarded( + context = ctx, + onShowingAd = { + onShowToast("Showing rewarded ad") + shouldShowRewardAd = false + }, + onUserEarnedRewardListener = { + onShowToast("Reward granted") + }, + ) + } + if (shouldShowInterstitialAd) { + showInterstitial( + context = ctx, + onShowingAd = { + onShowToast("Showing interstitial ad") + shouldShowInterstitialAd = false + }, + onLoadedAd = { + onShowToast("Loaded interstitial ad") + } + ) + } + Column { Row( - modifier = Modifier - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically + modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { Row(Modifier.padding(end = 8.dp)) { Text(text = "Sort by:", fontSize = 20.sp, fontWeight = FontWeight.Bold) @@ -95,18 +142,22 @@ fun ShoppingListScreen( Row(Modifier.horizontalScroll(rememberScrollState())) { SortType.entries.forEach { sortType -> Row( - modifier = Modifier - .clickable { onEvent(ShoppingListEvent.SetSortType(sortType)) }, - verticalAlignment = Alignment.CenterVertically + modifier = Modifier.clickable { + onEvent( + ShoppingListEvent.SetSortType( + sortType + ) + ) + }, verticalAlignment = Alignment.CenterVertically ) { - RadioButton( - selected = state.sortType == sortType, + RadioButton(selected = state.sortType == sortType, onClick = { onEvent(ShoppingListEvent.SetSortType(sortType)) }) Text(text = sortType.name, fontSize = 16.sp) } } } } + Divider( thickness = 2.dp, color = Color.LightGray, @@ -115,35 +166,38 @@ fun ShoppingListScreen( LazyColumn( contentPadding = padding, - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .fillMaxSize() + .weight(2f), verticalArrangement = Arrangement.spacedBy(16.dp) ) { - items(state.shoppingListItems, key = {shoppingListItem -> if (shoppingListItem.id!==null) shoppingListItem.id else 0}) { shoppingItem -> - val dismissState = rememberDismissState( - confirmValueChange = { - when (it) { - DismissValue.DismissedToEnd -> { - onEvent(ShoppingListEvent.DeleteShoppingListItem(shoppingItem)) - onShowToast("Deleted ${shoppingItem.name} shopping list item via swipe gesture") - true - } - DismissValue.DismissedToStart -> { - onEvent( - ShoppingListEvent.OpenEditingShoppingListItem( - shoppingItem - ) + items(state.shoppingListItems, + key = { shoppingListItem -> if (shoppingListItem.id !== null) shoppingListItem.id else 0 }) { shoppingItem -> + val dismissState = rememberDismissState(confirmValueChange = { + when (it) { + DismissValue.DismissedToEnd -> { + onEvent(ShoppingListEvent.DeleteShoppingListItem(shoppingItem)) + onShowToast("Deleted ${shoppingItem.name} shopping list item via swipe gesture") + true + } + + DismissValue.DismissedToStart -> { + onEvent( + ShoppingListEvent.OpenEditingShoppingListItem( + shoppingItem ) - onShowToast("Opened ${shoppingItem.name} shopping list item edit dialog via swipe gesture") - false - } - else -> { - onShowToast("Swipe gesture aborted") - false - } + ) + onShowToast("Opened ${shoppingItem.name} shopping list item edit dialog via swipe gesture") + false } - }) - SwipeToDismiss( - state = dismissState, + + else -> { + onShowToast("Swipe gesture aborted") + false + } + } + }) + SwipeToDismiss(state = dismissState, background = { SwipeBackground(dismissState = dismissState) }, dismissContent = { Row( @@ -162,10 +216,9 @@ fun ShoppingListScreen( } IconButton(onClick = { - onEvent(ShoppingListEvent.DeleteShoppingListItem(shoppingItem)) - .also { - onShowToast("Deleted shopping list item ${shoppingItem.name}") - } + onEvent(ShoppingListEvent.DeleteShoppingListItem(shoppingItem)).also { + onShowToast("Deleted shopping list item ${shoppingItem.name}") + } }) { Icon( imageVector = Icons.Default.Delete, @@ -188,20 +241,6 @@ fun ShoppingListScreen( } }) } - item { - Row( - modifier = Modifier - .width(280.dp) - .height(70.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "Empty item to fill up room so that the last item's edit and delete button does not go under FAB.", - fontSize = 12.sp, - color = Color.Gray - ) - } - } } } } @@ -214,98 +253,85 @@ fun AddShoppingListItemDialog( onShowToast: (String) -> Unit?, modifier: Modifier = Modifier, ) { - AlertDialog( - modifier = modifier, - onDismissRequest = { - if (state.isAddingNewShoppingListItem) { - onEvent(ShoppingListEvent.CloseAddingNewShoppingListItemDialog) - } else if (state.isEditingShoppingListItem) { - onEvent(ShoppingListEvent.CloseEditingShoppingListItem) - } - }, - title = { Text(text = "Add new shopping list item") }, - text = { - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { - val shoppingListItem = state.newShoppingListItem + AlertDialog(modifier = modifier, onDismissRequest = { + if (state.isAddingNewShoppingListItem) { + onEvent(ShoppingListEvent.CloseAddingNewShoppingListItemDialog) + } else if (state.isEditingShoppingListItem) { + onEvent(ShoppingListEvent.CloseEditingShoppingListItem) + } + }, title = { Text(text = "Add new shopping list item") }, text = { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + val shoppingListItem = state.newShoppingListItem - TextField( - value = shoppingListItem.name, - onValueChange = { onEvent(ShoppingListEvent.SetName(it)) }, - label = { Text(text = "Item Name") }, - placeholder = { Text(text = "Item Name") }, - ) - TextField( - value = shoppingListItem.count, - label = { Text(text = "Count") }, - placeholder = { Text(text = "Count") }, - onValueChange = { - onEvent(ShoppingListEvent.SetCount(count = it)) - }, - keyboardOptions = KeyboardOptions().copy( - autoCorrect = false, - keyboardType = KeyboardType.NumberPassword - ), - leadingIcon = { - Text(text = "🧮", fontSize = 24.sp) - } - ) - TextField( - value = shoppingListItem.price, - label = { Text(text = "Price") }, - placeholder = { Text(text = "Price") }, - onValueChange = { - onEvent(ShoppingListEvent.SetPrice(price = it)) - }, - keyboardOptions = KeyboardOptions().copy( - autoCorrect = false, - keyboardType = KeyboardType.Decimal - ), - leadingIcon = { - Text(text = "💶", fontSize = 24.sp) - } - ) + TextField( + value = shoppingListItem.name, + onValueChange = { onEvent(ShoppingListEvent.SetName(it)) }, + label = { Text(text = "Item Name") }, + placeholder = { Text(text = "Item Name") }, + ) + TextField(value = shoppingListItem.count, + label = { Text(text = "Count") }, + placeholder = { Text(text = "Count") }, + onValueChange = { + onEvent(ShoppingListEvent.SetCount(count = it)) + }, + keyboardOptions = KeyboardOptions().copy( + autoCorrect = false, keyboardType = KeyboardType.NumberPassword + ), + leadingIcon = { + Text(text = "🧮", fontSize = 24.sp) + }) + TextField(value = shoppingListItem.price, + label = { Text(text = "Price") }, + placeholder = { Text(text = "Price") }, + onValueChange = { + onEvent(ShoppingListEvent.SetPrice(price = it)) + }, + keyboardOptions = KeyboardOptions().copy( + autoCorrect = false, keyboardType = KeyboardType.Decimal + ), + leadingIcon = { + Text(text = "💶", fontSize = 24.sp) + }) + } + }, confirmButton = { + Button(onClick = { + if (state.newShoppingListItem.name.length < 3) { + onShowToast("Item Name is too short!") + return@Button + } + if (state.newShoppingListItem.count.toIntOrNull() === null) { + onShowToast("Invalid value for Count! Failed to convert value to Int.") + return@Button + } + if (state.newShoppingListItem.price.toFloatOrNull() === null) { + onShowToast("Invalid value for Price! Failed to convert value to Float.") + return@Button } - }, - confirmButton = { - Button(onClick = { - if (state.newShoppingListItem.name.length < 3) { - onShowToast("Item Name is too short!") - return@Button - } - if (state.newShoppingListItem.count.toIntOrNull() === null) { - onShowToast("Invalid value for Count! Failed to convert value to Int.") - return@Button - } - if (state.newShoppingListItem.price.toFloatOrNull() === null) { - onShowToast("Invalid value for Price! Failed to convert value to Float.") - return@Button - } - if (state.isAddingNewShoppingListItem) { - onEvent(ShoppingListEvent.InsertNewShoppingListItemToDb).also { onShowToast("Added new item to shopping list!") } - } else if (state.isEditingShoppingListItem) { - onEvent(ShoppingListEvent.UpdateCurrentlyEditingShoppingListItem).also { - onShowToast( - "Updated shopping list item ${state.currentlyEditingShoppingListItem?.name}!" - ) - } + if (state.isAddingNewShoppingListItem) { + onEvent(ShoppingListEvent.InsertNewShoppingListItemToDb).also { onShowToast("Added new item to shopping list!") } + } else if (state.isEditingShoppingListItem) { + onEvent(ShoppingListEvent.UpdateCurrentlyEditingShoppingListItem).also { + onShowToast( + "Updated shopping list item ${state.currentlyEditingShoppingListItem?.name}!" + ) } - }) { - Text(text = if (state.isEditingShoppingListItem) "Update" else "Insert") } - }, - dismissButton = { - Button(onClick = { - if (state.isAddingNewShoppingListItem) { - onEvent(ShoppingListEvent.CloseAddingNewShoppingListItemDialog) - } else if (state.isEditingShoppingListItem) { - onEvent(ShoppingListEvent.CloseEditingShoppingListItem) - } - }) { - Text(text = "Close") + }) { + Text(text = if (state.isEditingShoppingListItem) "Update" else "Insert") + } + }, dismissButton = { + Button(onClick = { + if (state.isAddingNewShoppingListItem) { + onEvent(ShoppingListEvent.CloseAddingNewShoppingListItemDialog) + } else if (state.isEditingShoppingListItem) { + onEvent(ShoppingListEvent.CloseEditingShoppingListItem) } + }) { + Text(text = "Close") } - ) + }) } @Composable @@ -340,9 +366,30 @@ fun SwipeBackground(dismissState: DismissState) { contentAlignment = alignment ) { Icon( - icon, - contentDescription = "Delete", - modifier = Modifier.scale(scale) + icon, contentDescription = "Delete", modifier = Modifier.scale(scale) ) } } + + +@Composable +fun AdMobBannersAd( + modifier: Modifier = Modifier, contentAlignment: Alignment = Alignment.Center +) { + Box(modifier = modifier.then(Modifier.fillMaxSize()), contentAlignment = contentAlignment) { + AndroidView( + // on below line specifying width for ads. + factory = { context -> + // on below line specifying ad view. + AdView(context).apply { + // on below line specifying ad size + setAdSize(AdSize.BANNER) + // on below line specifying ad unit id + // currently added a test ad unit id. + adUnitId = "ca-app-pub-3940256099942544/6300978111" + // calling load ad to load our ad. + loadAd(AdRequest.Builder().build()) + } + }) + } +}