From e9b085dd7c457144a3a3345bd681f8be0262d28b Mon Sep 17 00:00:00 2001 From: argzdev Date: Wed, 24 May 2023 02:42:02 +0800 Subject: [PATCH] - Added ComposeMainActivity - Transferred business logic to ViewModel sharable to the `KotlinMainActivity` and `ComposeMainActivity` --- inappmessaging/app/build.gradle | 1 + .../app/src/main/AndroidManifest.xml | 13 +- .../fiamquickstart/EntryChoiceActivity.kt | 21 ++- .../kotlin/ComposeMainActivity.kt | 162 ++++++++++++++++++ .../kotlin/InAppMessagingViewModel.kt | 66 +++++++ .../kotlin/KotlinMainActivity.kt | 36 ++-- .../fiamquickstart/kotlin/theme/Color.kt | 11 ++ .../fiamquickstart/kotlin/theme/Shape.kt | 11 ++ .../fiamquickstart/kotlin/theme/Theme.kt | 48 ++++++ .../fiamquickstart/kotlin/theme/Type.kt | 34 ++++ inappmessaging/gradle.properties | 2 +- 11 files changed, 364 insertions(+), 41 deletions(-) create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/ComposeMainActivity.kt create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/InAppMessagingViewModel.kt create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Color.kt create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Shape.kt create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Theme.kt create mode 100644 inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Type.kt diff --git a/inappmessaging/app/build.gradle b/inappmessaging/app/build.gradle index 00b6c2746..fa35f09ec 100644 --- a/inappmessaging/app/build.gradle +++ b/inappmessaging/app/build.gradle @@ -85,6 +85,7 @@ dependencies { implementation "androidx.compose.material:material:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" implementation 'androidx.activity:activity-compose:1.5.1' + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/inappmessaging/app/src/main/AndroidManifest.xml b/inappmessaging/app/src/main/AndroidManifest.xml index f9816bcd6..e8fd0ab3e 100644 --- a/inappmessaging/app/src/main/AndroidManifest.xml +++ b/inappmessaging/app/src/main/AndroidManifest.xml @@ -10,16 +10,11 @@ android:theme="@style/AppTheme"> - - + android:name="com.google.firebase.fiamquickstart.java.MainActivity"/> - + android:name="com.google.firebase.fiamquickstart.kotlin.KotlinMainActivity"/> + diff --git a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/EntryChoiceActivity.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/EntryChoiceActivity.kt index efe54c42c..d29b9fa50 100644 --- a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/EntryChoiceActivity.kt +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/EntryChoiceActivity.kt @@ -4,20 +4,25 @@ import android.content.Intent import com.firebase.example.internal.BaseEntryChoiceActivity import com.firebase.example.internal.Choice import com.google.firebase.fiamquickstart.java.MainActivity +import com.google.firebase.fiamquickstart.kotlin.ComposeMainActivity import com.google.firebase.fiamquickstart.kotlin.KotlinMainActivity class EntryChoiceActivity : BaseEntryChoiceActivity() { override fun getChoices(): List { return listOf( - Choice( - "Java", - "Run the Firebase In App Messaging quickstart written in Java.", - Intent(this, MainActivity::class.java)), - Choice( - "Kotlin", - "Run the Firebase In App Messaging quickstart written in Kotlin.", - Intent(this, KotlinMainActivity::class.java)) + Choice( + "Java", + "Run the Firebase In App Messaging quickstart written in Java.", + Intent(this, MainActivity::class.java)), + Choice( + "Kotlin", + "Run the Firebase In App Messaging quickstart written in Kotlin.", + Intent(this, KotlinMainActivity::class.java)), + Choice( + "Compose", + "Run the Firebase In App Messaging quickstart written in Compose.", + Intent(this, ComposeMainActivity::class.java)) ) } } diff --git a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/ComposeMainActivity.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/ComposeMainActivity.kt new file mode 100644 index 000000000..75168ed5e --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/ComposeMainActivity.kt @@ -0,0 +1,162 @@ +package com.google.firebase.fiamquickstart.kotlin + +import android.os.Bundle +import androidx.activity.compose.setContent +import androidx.appcompat.app.AppCompatActivity +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Scaffold +import androidx.compose.material.SnackbarHostState +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.firebase.fiamquickstart.R +import com.google.firebase.fiamquickstart.kotlin.ui.theme.InAppMessagingTheme +import kotlinx.coroutines.launch + +class ComposeMainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setContent { + InAppMessagingTheme { + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colors.background + ) { + MainAppView() + } + } + } + } + + companion object { + private const val TAG = "Compose-FIAM-Quickstart" + } +} + +@Composable +fun MainAppView( + inAppMessagingViewModel: InAppMessagingViewModel = viewModel(factory = InAppMessagingViewModel.Factory) +) { + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState) + + Scaffold( + scaffoldState = scaffoldState, + content = { + Column( + modifier = Modifier + .fillMaxSize() + .padding(it) + ) { + MainContent( + _installationsId = inAppMessagingViewModel.installationsId.collectAsState(""), + triggerEvent = { + inAppMessagingViewModel.triggerEvent() + scope.launch { + snackbarHostState.showSnackbar("engagement_party' event triggered!") + } + } + ) + } + } + ) +} + +@Composable +fun MainContent( + _installationsId: State = mutableStateOf(""), + triggerEvent: ()-> Unit = {} +) { + val installationsId by remember { _installationsId } + + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth(), + ) { + Image( + painter = painterResource(R.drawable.firebase_lockup_400), + contentDescription = "", + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + alignment = Alignment.Center + ) + + Text( + text = stringResource(R.string.textview_text), + fontSize = 18.sp, + style = MaterialTheme.typography.h6, + modifier = Modifier.padding(top = 8.dp, start = 8.dp, end = 8.dp) + ) + + Text( + text = stringResource(R.string.warning_fresh_install), + fontSize = 18.sp, + style = MaterialTheme.typography.h6, + modifier = Modifier.padding(top = 16.dp, start = 8.dp, end = 8.dp, bottom = 8.dp) + ) + + Text( + text = if(installationsId.isEmpty()){ + "Device Instance ID: 1234" + } else { + stringResource(R.string.installation_id_fmt, installationsId) + }, + fontSize = 18.sp, + style = MaterialTheme.typography.h6, + modifier = Modifier.padding(top = 16.dp, start = 8.dp, end = 8.dp, bottom = 8.dp) + ) + + Button( + modifier = Modifier + .fillMaxWidth() + .padding(8.dp), + colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorPrimary)), + onClick = { + triggerEvent() + } + ) { + Text( + text = stringResource(R.string.button_text).uppercase(), + color = Color.White + ) + } + } +} + + +@Composable +@Preview(showBackground = true) +fun MainContentPreview(){ + InAppMessagingTheme { + MainContent() + } +} diff --git a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/InAppMessagingViewModel.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/InAppMessagingViewModel.kt new file mode 100644 index 000000000..024cd06b8 --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/InAppMessagingViewModel.kt @@ -0,0 +1,66 @@ +package com.google.firebase.fiamquickstart.kotlin + +import android.os.Bundle +import android.util.Log +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewModelScope +import androidx.lifecycle.viewmodel.CreationExtras +import com.google.firebase.analytics.FirebaseAnalytics +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.inappmessaging.FirebaseInAppMessaging +import com.google.firebase.inappmessaging.ktx.inAppMessaging +import com.google.firebase.installations.FirebaseInstallations +import com.google.firebase.installations.ktx.installations +import com.google.firebase.ktx.Firebase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.tasks.await + +class InAppMessagingViewModel( + private val firebaseAnalytics: FirebaseAnalytics, + firebaseIam: FirebaseInAppMessaging, + private val firebaseInstallations: FirebaseInstallations, +): ViewModel() { + + private val _installationsId = MutableStateFlow("") + val installationsId: StateFlow = _installationsId + + init { + firebaseIam.isAutomaticDataCollectionEnabled = true + firebaseIam.setMessagesSuppressed(false) + + viewModelScope.launch { + try { + val id = firebaseInstallations.id.await() + _installationsId.value = id + } catch (e: Exception) { + Log.e(TAG, e.toString()) + } + } + } + + fun triggerEvent(){ + firebaseAnalytics.logEvent("engagement_party", Bundle()) + } + + companion object { + const val TAG = "InAppMessagingViewModel" + + // Used to inject this ViewModel's dependencies + // See also: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories + val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras + ): T { + val firebaseAnalytics = Firebase.analytics + val firebaseIam = Firebase.inAppMessaging + val firebaseInstallations = Firebase.installations + return InAppMessagingViewModel(firebaseAnalytics, firebaseIam, firebaseInstallations) as T + } + } + } +} \ No newline at end of file diff --git a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/KotlinMainActivity.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/KotlinMainActivity.kt index 807a55ed8..c2c459800 100644 --- a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/KotlinMainActivity.kt +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/KotlinMainActivity.kt @@ -1,51 +1,41 @@ package com.google.firebase.fiamquickstart.kotlin import android.os.Bundle -import android.util.Log +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope import com.google.android.material.snackbar.Snackbar -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.analytics.ktx.analytics import com.google.firebase.fiamquickstart.R import com.google.firebase.fiamquickstart.databinding.ActivityMainBinding -import com.google.firebase.inappmessaging.FirebaseInAppMessaging -import com.google.firebase.inappmessaging.ktx.inAppMessaging -import com.google.firebase.installations.ktx.installations -import com.google.firebase.ktx.Firebase +import kotlinx.coroutines.launch class KotlinMainActivity : AppCompatActivity() { - private lateinit var firebaseAnalytics: FirebaseAnalytics - private lateinit var firebaseIam: FirebaseInAppMessaging + private val viewModel: InAppMessagingViewModel by viewModels { InAppMessagingViewModel.Factory } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - firebaseAnalytics = Firebase.analytics - firebaseIam = Firebase.inAppMessaging - - firebaseIam.isAutomaticDataCollectionEnabled = true - firebaseIam.setMessagesSuppressed(false) - binding.eventTriggerButton.setOnClickListener { view -> - firebaseAnalytics.logEvent("engagement_party", Bundle()) + viewModel.triggerEvent() Snackbar.make(view, "'engagement_party' event triggered!", Snackbar.LENGTH_LONG) - .setAction("Action", null) - .show() + .setAction("Action", null) + .show() } // Get and display/log the installation id - Firebase.installations.getId() - .addOnSuccessListener { id -> - binding.installationIdText.text = getString(R.string.installation_id_fmt, id) - Log.d(TAG, "Installation ID: $id") + lifecycleScope.launch { + viewModel.installationsId.collect { + if (it.isNotEmpty()) { + binding.installationIdText.text = getString(R.string.installation_id_fmt, it) } + } + } } companion object { - private const val TAG = "FIAM-Quickstart" } } diff --git a/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Color.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Color.kt new file mode 100644 index 000000000..b27e6b03c --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Color.kt @@ -0,0 +1,11 @@ +package com.google.firebase.fiamquickstart.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/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Shape.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Shape.kt new file mode 100644 index 000000000..bbbc4c465 --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.google.firebase.fiamquickstart.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/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Theme.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Theme.kt new file mode 100644 index 000000000..d60199da8 --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Theme.kt @@ -0,0 +1,48 @@ +package com.google.firebase.fiamquickstart.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 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun InAppMessagingTheme( + 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/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Type.kt b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Type.kt new file mode 100644 index 000000000..0f280144f --- /dev/null +++ b/inappmessaging/app/src/main/java/com/google/firebase/fiamquickstart/kotlin/theme/Type.kt @@ -0,0 +1,34 @@ +package com.google.firebase.fiamquickstart.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 + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/inappmessaging/gradle.properties b/inappmessaging/gradle.properties index aac7c9b46..29b531a1d 100644 --- a/inappmessaging/gradle.properties +++ b/inappmessaging/gradle.properties @@ -10,7 +10,7 @@ # Specifies the JVM arguments used for the daemon process. # The setting is particularly useful for tweaking memory settings. org.gradle.jvmargs=-Xmx1536m - +android.useAndroidX=true # When configured, Gradle will run in incubating parallel mode. # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects