diff --git a/analytics/app/build.gradle b/analytics/app/build.gradle index 53a4704f2..ea9f96465 100644 --- a/analytics/app/build.gradle +++ b/analytics/app/build.gradle @@ -8,12 +8,12 @@ check.dependsOn 'assembleDebugAndroidTest' android { namespace 'com.google.firebase.quickstart.analytics' - compileSdk 33 + compileSdk 34 defaultConfig { applicationId "com.google.firebase.quickstart.analytics" minSdk 21 // minSdk would be 19 without compose - targetSdk 33 + targetSdk 34 versionCode 1 versionName "1.0" testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' @@ -77,6 +77,9 @@ dependencies { implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.activity:activity-compose:1.5.1' + implementation 'androidx.compose.foundation:foundation-android:1.6.8' + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' androidTestImplementation 'androidx.test:rules:1.4.0' androidTestImplementation 'androidx.test:runner:1.4.0' diff --git a/analytics/app/src/main/AndroidManifest.xml b/analytics/app/src/main/AndroidManifest.xml index ae27d65cf..7c7971f4c 100644 --- a/analytics/app/src/main/AndroidManifest.xml +++ b/analytics/app/src/main/AndroidManifest.xml @@ -13,6 +13,9 @@ + + { return listOf( - Choice( - "Java", - "Run the Firebase Analytics quickstart written in Java.", - Intent( - this, - com.google.firebase.quickstart.analytics.java.MainActivity::class.java)), - Choice( - "Kotlin", - "Run the Firebase Analytics quickstart written in Kotlin.", - Intent( - this, - com.google.firebase.quickstart.analytics.kotlin.MainActivity::class.java)) + Choice( + "Java", + "Run the Firebase Analytics quickstart written in Java.", + Intent( + this, + com.google.firebase.quickstart.analytics.java.MainActivity::class.java)), + Choice( + "Kotlin", + "Run the Firebase Analytics quickstart written in Kotlin.", + Intent( + this, + com.google.firebase.quickstart.analytics.kotlin.MainActivity::class.java)), + Choice( + "Compose", + "Run the Firebase Analytics quickstart written in Compose.", + Intent( + this, + com.google.firebase.quickstart.analytics.kotlin.ComposeMainActivity::class.java)) ) } } diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ComposeMainActivity.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ComposeMainActivity.kt new file mode 100644 index 000000000..fbf1d7eed --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ComposeMainActivity.kt @@ -0,0 +1,319 @@ +package com.google.firebase.quickstart.analytics.kotlin + +import android.content.Context +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material.AlertDialog +import androidx.compose.material.Button +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.RadioButton +import androidx.compose.material.Scaffold +import androidx.compose.material.SnackbarHost +import androidx.compose.material.SnackbarHostState +import androidx.compose.material.Surface +import androidx.compose.material.Tab +import androidx.compose.material.TabRow +import androidx.compose.material.TabRowDefaults +import androidx.compose.material.TabRowDefaults.tabIndicatorOffset +import androidx.compose.material.Text +import androidx.compose.material.TopAppBar +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Share +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringArrayResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.core.app.ShareCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.preference.PreferenceManager +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.ktx.Firebase +import com.google.firebase.quickstart.analytics.R +import com.google.firebase.quickstart.analytics.kotlin.ui.theme.FirebaseAnalyticsTheme +import kotlinx.coroutines.launch + +class ComposeMainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + FirebaseAnalyticsTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + MainAppView() + } + } + } + } +} + +@Composable +fun MainAppView( + lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current +) { + val context = LocalContext.current + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + val analyticsViewModel: FirebaseAnalyticsViewModel = viewModel( + factory = FirebaseAnalyticsViewModel.Factory(Firebase.analytics, sharedPreferences) + ) + val snackbarHostState = remember { SnackbarHostState() } + + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_CREATE) { + recordImageView(analyticsViewModel, context) + } else if (event == Lifecycle.Event.ON_RESUME) { + recordScreenView(analyticsViewModel, context) + } + } + + lifecycleOwner.lifecycle.addObserver(observer) + + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + // Load favorite food on initial composition + LaunchedEffect(Unit) { + if(analyticsViewModel.userFavoriteFood.value == null) + analyticsViewModel.showFavoriteFoodDialog.value = true + } + + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + modifier = Modifier.fillMaxSize(), + topBar = { + MainAppBar(analyticsViewModel) + }, + content = { paddingValues -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(paddingValues), + ) { + MainContent(analyticsViewModel) + FavoriteFoodDialog(analyticsViewModel, snackbarHostState) + } + } + ) +} + +@Composable +fun MainAppBar(analyticsViewModel: FirebaseAnalyticsViewModel) { + val context = LocalContext.current + TopAppBar( + title = { + Text( + text = stringResource(R.string.app_name), + style = MaterialTheme.typography.h6, + textAlign = TextAlign.Center, + modifier = Modifier.padding(8.dp), + color = Color.White + ) + }, + backgroundColor = colorResource(R.color.colorPrimary), + actions = { + IconButton(onClick = { + val imageTitle = getCurrentImageTitle(context, analyticsViewModel.selectedImageIndex.value) + val text = "I'd love you to hear about $imageTitle" + + ShareCompat.IntentBuilder(context).setType("text/plain") + .setText(text) + .startChooser() + + analyticsViewModel.recordShareEvent(imageTitle, text) + }) { + Icon(Icons.Filled.Share, contentDescription = "Share") + } + } + ) +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun MainContent(analyticsViewModel: FirebaseAnalyticsViewModel) { + val context = LocalContext.current + val coroutineScope = rememberCoroutineScope() + val pagerState = rememberPagerState(initialPage = 0, pageCount = { Constants.IMAGE_INFOS.size }) + + LaunchedEffect(pagerState) { + snapshotFlow { pagerState.targetPage }.collect { page -> + analyticsViewModel.setSelectedImageIndex(page) + recordImageView(analyticsViewModel, context) + recordScreenView(analyticsViewModel, context) + } + } + + TabRow( + backgroundColor = Color.White, + selectedTabIndex = pagerState.currentPage, + indicator = { tabPositions -> + TabRowDefaults.Indicator( + modifier = Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage]), + color = colorResource(id = R.color.colorPrimary) + ) + }, + ) { + Constants.IMAGE_INFOS.forEachIndexed { index, info -> + val isSelected = pagerState.currentPage == index + Tab( + text = { + Text(text = stringResource(id = info.title), + color = if(isSelected) colorResource(id = R.color.colorPrimary) else Color.Black) + }, + selected = isSelected, + onClick = { + coroutineScope.launch { + pagerState.animateScrollToPage(index) + } + }, + ) + } + } + //Image Pager + HorizontalPager( + state = pagerState, + modifier = Modifier.fillMaxSize() + ) { page -> + ImageCard(imageInfo = Constants.IMAGE_INFOS[page]) + } +} + +@Composable +fun ImageCard(imageInfo: ImageInfo) { + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Image( + painter = painterResource(id = imageInfo.image), + contentDescription = stringResource(id = imageInfo.title), + modifier = Modifier + .shadow(elevation = 2.dp, shape = CircleShape) + .background(Color.White, shape = CircleShape) + .padding(16.dp) + ) + } +} + +@Composable +fun FavoriteFoodDialog( + analyticsViewModel: FirebaseAnalyticsViewModel, + snackbarHostState: SnackbarHostState +) { + if (analyticsViewModel.showFavoriteFoodDialog.value) { + val coroutineScope = rememberCoroutineScope() + val choices = stringArrayResource(id = R.array.food_items) + var selectedItem by remember { mutableIntStateOf(0) } + + AlertDialog( + onDismissRequest = { + analyticsViewModel.showFavoriteFoodDialog.value = false + }, + title = { Text(stringResource(id = R.string.food_dialog_title)) }, + text = { + Column { + choices.forEachIndexed { index, item -> + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.clickable { selectedItem = index } + ) { + RadioButton( + selected = selectedItem == index, + onClick = { selectedItem = index } + ) + Text(item) + } + } + } + }, + confirmButton = { + Button(onClick = { + val selectedFood = choices[selectedItem] + analyticsViewModel.setUserFavoriteFood(selectedFood) + coroutineScope.launch { + snackbarHostState.showSnackbar("Favorite Food selected: $selectedFood") + } + }) { + Text("OK") + } + } + ) + } +} + +private fun getCurrentImageTitle(context: Context, position: Int): String { + val imageDetails = Constants.IMAGE_INFOS[position] + return context.getString(imageDetails.title) +} + +private fun getCurrentImageId(context: Context, position: Int): String { + val imageDetails = Constants.IMAGE_INFOS[position] + return context.getString(imageDetails.id) +} + +private fun recordScreenView(analyticsViewModel: FirebaseAnalyticsViewModel, context: Context) { + val position = analyticsViewModel.selectedImageIndex.value + val imageId = getCurrentImageId(context, position) + val imageTitle = getCurrentImageTitle(context, position) + + analyticsViewModel.recordScreenView("${imageId}-${imageTitle}", "ComposeMainActivity") +} + +private fun recordImageView(analyticsViewModel: FirebaseAnalyticsViewModel, context: Context) { + val position = analyticsViewModel.selectedImageIndex.value + val imageId = getCurrentImageId(context, position) + val imageTitle = getCurrentImageTitle(context, position) + + analyticsViewModel.recordImageView(imageId, imageTitle) +} + +@Preview(showBackground = true) +@Composable +fun MainAppPreview() { + FirebaseAnalyticsTheme { + MainAppView() + } +} \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/Constants.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/Constants.kt new file mode 100644 index 000000000..773d2b81d --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/Constants.kt @@ -0,0 +1,16 @@ +package com.google.firebase.quickstart.analytics.kotlin + +import com.google.firebase.quickstart.analytics.R + +class Constants { + companion object { + const val KEY_FAVORITE_FOOD = "favorite_food" + + val IMAGE_INFOS = arrayOf( + ImageInfo(R.drawable.favorite, R.string.pattern1_title, R.string.pattern1_id), + ImageInfo(R.drawable.flash, R.string.pattern2_title, R.string.pattern2_id), + ImageInfo(R.drawable.face, R.string.pattern3_title, R.string.pattern3_id), + ImageInfo(R.drawable.whitebalance, R.string.pattern4_title, R.string.pattern4_id) + ) + } +} \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/FirebaseAnalyticsViewModel.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/FirebaseAnalyticsViewModel.kt new file mode 100644 index 000000000..3f1e48b94 --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/FirebaseAnalyticsViewModel.kt @@ -0,0 +1,94 @@ +package com.google.firebase.quickstart.analytics.kotlin + +import android.content.SharedPreferences +import androidx.compose.runtime.MutableState +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import com.google.firebase.analytics.FirebaseAnalytics +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.analytics.ktx.logEvent +import com.google.firebase.ktx.Firebase + +class FirebaseAnalyticsViewModel ( + private val firebaseAnalytics: FirebaseAnalytics, + private val sharedPreferences: SharedPreferences +): ViewModel() { + + private val _selectedImageIndex = mutableIntStateOf(0) + val selectedImageIndex: MutableState = _selectedImageIndex + + private val _userFavoriteFood = mutableStateOf(null) + val userFavoriteFood: MutableState = _userFavoriteFood + + private val _showFavoriteFoodDialog = mutableStateOf(false) + val showFavoriteFoodDialog: MutableState = _showFavoriteFoodDialog + + init { + getUserFavoriteFood() + if(_userFavoriteFood.value == null) { + _showFavoriteFoodDialog.value = true + } else { + setUserFavoriteFood(_userFavoriteFood.value) + } + } + + fun setSelectedImageIndex(index: Int) { + _selectedImageIndex.intValue = index + } + + fun setUserFavoriteFood(food: String?) { + _showFavoriteFoodDialog.value = false + _userFavoriteFood.value = food + sharedPreferences.edit() + .putString(Constants.KEY_FAVORITE_FOOD, food) + .apply() + + firebaseAnalytics.setUserProperty("favorite_food", food) + } + + private fun getUserFavoriteFood() { + _userFavoriteFood.value = sharedPreferences.getString(Constants.KEY_FAVORITE_FOOD, null) + } + + fun recordShareEvent(imageTitle: String, text: String) { + firebaseAnalytics.logEvent("share_image") { + param("image_name", imageTitle) + param("full_text", text) + } + } + + fun recordScreenView(screenName: String, screenClass: String) { + firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW) { + param(FirebaseAnalytics.Param.SCREEN_NAME, screenName) + param(FirebaseAnalytics.Param.SCREEN_CLASS, screenClass) + } + } + + fun recordImageView(id: String, name: String) { + firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_ITEM) { + param(FirebaseAnalytics.Param.ITEM_ID, id) + param(FirebaseAnalytics.Param.ITEM_NAME, name) + param(FirebaseAnalytics.Param.CONTENT_TYPE, "image") + } + } + + companion object { + // Used to inject this ViewModel's dependencies + // See also: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories + fun Factory( + firebaseAnalytics: FirebaseAnalytics = Firebase.analytics, + sharedPreferences: SharedPreferences + ): ViewModelProvider.Factory = object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras + ): T { + return FirebaseAnalyticsViewModel(firebaseAnalytics, sharedPreferences) as T + } + } + } +} \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/MainActivity.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/MainActivity.kt index 003fd62fc..acb7c35a3 100644 --- a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/MainActivity.kt +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/MainActivity.kt @@ -1,11 +1,12 @@ package com.google.firebase.quickstart.analytics.kotlin -import android.annotation.SuppressLint +import android.content.Context import android.content.Intent +import android.content.SharedPreferences import android.os.Bundle -import android.util.Log import android.view.Menu import android.view.MenuItem +import androidx.activity.viewModels import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment @@ -16,32 +17,20 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator -import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.analytics.ktx.logEvent import com.google.firebase.ktx.Firebase import com.google.firebase.quickstart.analytics.R import com.google.firebase.quickstart.analytics.databinding.ActivityMainBinding -import com.google.firebase.quickstart.analytics.java.MainActivity -import com.google.firebase.quickstart.analytics.kotlin.MainActivity.Companion.IMAGE_INFOS import java.util.Locale - /** * Activity which displays numerous background images that may be viewed. These background images * are shown via {@link ImageFragment}. */ class MainActivity : AppCompatActivity() { + companion object { private const val TAG = "MainActivity" - private const val KEY_FAVORITE_FOOD = "favorite_food" - - private val IMAGE_INFOS = arrayOf( - ImageInfo(R.drawable.favorite, R.string.pattern1_title, R.string.pattern1_id), - ImageInfo(R.drawable.flash, R.string.pattern2_title, R.string.pattern2_id), - ImageInfo(R.drawable.face, R.string.pattern3_title, R.string.pattern3_id), - ImageInfo(R.drawable.whitebalance, R.string.pattern4_title, R.string.pattern4_id) - ) } private lateinit var binding: ActivityMainBinding @@ -52,34 +41,35 @@ class MainActivity : AppCompatActivity() { */ private lateinit var imagePagerAdapter: ImagePagerAdapter - /** - * The `FirebaseAnalytics` used to record screen views. - */ - // [START declare_analytics] - private lateinit var firebaseAnalytics: FirebaseAnalytics - // [END declare_analytics] + private lateinit var context: Context + private lateinit var sharedPrefs: SharedPreferences + + // Injects FirebaseAnalytics and app measurement configuration from the factory for centralized management. + private lateinit var viewModel: FirebaseAnalyticsViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + context = applicationContext + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context) + // [START declare_analytics] // [START shared_app_measurement] - // Obtain the FirebaseAnalytics instance. - firebaseAnalytics = Firebase.analytics + viewModel = viewModels { + FirebaseAnalyticsViewModel.Factory(Firebase.analytics, sharedPrefs) + }.value // [END shared_app_measurement] + // [END declare_analytics] // On first app open, ask the user his/her favorite food. Then set this as a user property // on all subsequent opens. - val userFavoriteFood = getUserFavoriteFood() - if (userFavoriteFood == null) { + if (viewModel.showFavoriteFoodDialog.value) { askFavoriteFood() - } else { - setUserFavoriteFood(userFavoriteFood) } // Create the adapter that will return a fragment for each image. - imagePagerAdapter = ImagePagerAdapter(supportFragmentManager, IMAGE_INFOS, lifecycle) + imagePagerAdapter = ImagePagerAdapter(supportFragmentManager, Constants.IMAGE_INFOS, lifecycle) // Set up the ViewPager with the pattern adapter. binding.viewPager.adapter = imagePagerAdapter @@ -95,7 +85,7 @@ class MainActivity : AppCompatActivity() { val tabLayout: TabLayout = binding.tabLayout TabLayoutMediator(tabLayout, binding.viewPager) { tab, position -> - tab.setText(IMAGE_INFOS[position].title) + tab.setText(Constants.IMAGE_INFOS[position].title) }.attach() // Send initial screen screen view hit. @@ -118,37 +108,14 @@ class MainActivity : AppCompatActivity() { .setTitle(R.string.food_dialog_title) .setItems(choices) { _, which -> val food = choices[which] - setUserFavoriteFood(food) - }.create() + // [START user_property] + viewModel.setUserFavoriteFood(food) + // [END user_property] + }.create() ad.show() } - /** - * Get the user's favorite food from shared preferences. - * @return favorite food, as a string. - */ - private fun getUserFavoriteFood(): String? { - return PreferenceManager.getDefaultSharedPreferences(this) - .getString(KEY_FAVORITE_FOOD, null) - } - - /** - * Set the user's favorite food as an app measurement user property and in shared preferences. - * @param food the user's favorite food. - */ - private fun setUserFavoriteFood(food: String) { - Log.d(TAG, "setFavoriteFood: $food") - - PreferenceManager.getDefaultSharedPreferences(this).edit() - .putString(KEY_FAVORITE_FOOD, food) - .apply() - - // [START user_property] - firebaseAnalytics.setUserProperty("favorite_food", food) - // [END user_property] - } - override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.main, menu) return true @@ -167,10 +134,7 @@ class MainActivity : AppCompatActivity() { startActivity(sendIntent) // [START custom_event] - firebaseAnalytics.logEvent("share_image") { - param("image_name", name) - param("full_text", text) - } + viewModel.recordShareEvent(name, text) // [END custom_event] } return false @@ -183,7 +147,7 @@ class MainActivity : AppCompatActivity() { */ private fun getCurrentImageTitle(): String { val position = binding.viewPager.currentItem - val info = IMAGE_INFOS[position] + val info = Constants.IMAGE_INFOS[position] return getString(info.title) } @@ -194,7 +158,7 @@ class MainActivity : AppCompatActivity() { */ private fun getCurrentImageId(): String { val position = binding.viewPager.currentItem - val info = IMAGE_INFOS[position] + val info = Constants.IMAGE_INFOS[position] return getString(info.id) } @@ -207,11 +171,7 @@ class MainActivity : AppCompatActivity() { val name = getCurrentImageTitle() // [START image_view_event] - firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SELECT_ITEM) { - param(FirebaseAnalytics.Param.ITEM_ID, id) - param(FirebaseAnalytics.Param.ITEM_NAME, name) - param(FirebaseAnalytics.Param.CONTENT_TYPE, "image") - } + viewModel.recordImageView(id, name) // [END image_view_event] } @@ -224,10 +184,7 @@ class MainActivity : AppCompatActivity() { val screenName = "${getCurrentImageId()}-${getCurrentImageTitle()}" // [START set_current_screen] - firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW) { - param(FirebaseAnalytics.Param.SCREEN_NAME, screenName) - param(FirebaseAnalytics.Param.SCREEN_CLASS, "MainActivity") - } + viewModel.recordScreenView(screenName, "MainActivity") // [END set_current_screen] } diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Color.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Color.kt new file mode 100644 index 000000000..602e81512 --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.google.firebase.quickstart.analytics.kotlin.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val FirebaseBlue = Color(0xFF0288D1) // copied from colors.xml +val FirebaseBannerBlue = Color(0xFF039BE5) // copied from colors.xml +val FirebaseOrange = Color(0xFFFFA000) // copied from colors.xml \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Shape.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Shape.kt new file mode 100644 index 000000000..93070eb61 --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.google.firebase.quickstart.analytics.kotlin.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + small = RoundedCornerShape(16.dp), + medium = RoundedCornerShape(2.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Theme.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Theme.kt new file mode 100644 index 000000000..d426d69ed --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Theme.kt @@ -0,0 +1,38 @@ +package com.google.firebase.quickstart.analytics.kotlin.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors +import androidx.compose.runtime.Composable + +private val DarkColorPalette = darkColors( + primary = Purple80, + primaryVariant = PurpleGrey80, + secondary = Pink80 +) + +private val LightColorPalette = lightColors( + primary = FirebaseBlue, + primaryVariant = FirebaseBannerBlue, + secondary = FirebaseOrange +) + +@Composable +fun FirebaseAnalyticsTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable () -> Unit +) { + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette + } + + MaterialTheme( + colors = colors, + typography = Typography, + shapes = Shapes, + content = content + ) +} \ No newline at end of file diff --git a/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Type.kt b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Type.kt new file mode 100644 index 000000000..a0184e801 --- /dev/null +++ b/analytics/app/src/main/java/com/google/firebase/quickstart/analytics/kotlin/ui/theme/Type.kt @@ -0,0 +1,18 @@ +package com.google.firebase.quickstart.analytics.kotlin.ui.theme + +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + body1 = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) +) \ No newline at end of file