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