From a8a11dc35472be59f8133eb48fd33c80bf8b134a Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Thu, 19 Jan 2023 17:11:02 -0600 Subject: [PATCH 01/19] Added compose Added compose as an option to use Firebase --- config/app/build.gradle | 39 +++++- config/app/src/main/AndroidManifest.xml | 20 ++-- .../quickstart/config/EntryChoiceActivity.kt | 8 +- .../config/kotlin/MainComposeActivity.kt | 111 ++++++++++++++++++ .../config/kotlin/ui/theme/Color.kt | 11 ++ .../config/kotlin/ui/theme/Theme.kt | 69 +++++++++++ .../quickstart/config/kotlin/ui/theme/Type.kt | 34 ++++++ config/app/src/main/res/values/strings.xml | 3 +- config/build.gradle | 3 + config/gradle.properties | 2 +- 10 files changed, 286 insertions(+), 14 deletions(-) create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt diff --git a/config/app/build.gradle b/config/app/build.gradle index 17f01745ba..4f629ae35c 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -12,12 +12,15 @@ android { defaultConfig { applicationId "com.google.samples.quickstart.config" - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 33 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + vectorDrawables { + useSupportLibrary true + } } buildTypes { @@ -29,6 +32,22 @@ android { buildFeatures { viewBinding = true + compose true + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } + composeOptions { + kotlinCompilerExtensionVersion '1.3.2' + } + packagingOptions { + resources { + excludes += '/META-INF/{AL2.0,LGPL2.1}' + } } } @@ -37,6 +56,7 @@ dependencies { implementation project(":internal:chooserx") implementation 'com.google.android.material:material:1.7.0' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' // Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom) implementation platform('com.google.firebase:firebase-bom:31.1.0') @@ -50,9 +70,20 @@ dependencies { // For an optimal experience using Remote Config, add the Firebase SDK // for Google Analytics. This is recommended, but not required. implementation 'com.google.firebase:firebase-analytics' + implementation 'androidx.compose.material3:material3:1.0.0-alpha02' + + debugImplementation "androidx.fragment:fragment-testing:1.5.4" + // Jetpack Compose + implementation "androidx.compose.ui:ui:$compose_version" + implementation "androidx.compose.material:material:$compose_version" + implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" + implementation 'androidx.activity:activity-compose:1.5.1' + androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' - androidTestImplementation 'androidx.test:rules:1.5.0' - androidTestImplementation 'androidx.test:runner:1.5.1' - androidTestImplementation 'androidx.test.ext:junit:1.1.4' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" + debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" } diff --git a/config/app/src/main/AndroidManifest.xml b/config/app/src/main/AndroidManifest.xml index 6065a87b1b..0ab90089d6 100644 --- a/config/app/src/main/AndroidManifest.xml +++ b/config/app/src/main/AndroidManifest.xml @@ -5,20 +5,26 @@ android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:theme="@style/AppTheme" > - + android:theme="@style/AppTheme"> + + + - - + android:exported="true" + android:label="@string/app_name"> @@ -27,4 +33,4 @@ - + \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt index e6ffe34e8d..49a58074d2 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt @@ -19,7 +19,13 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() { "Run the Firebase Remote Config quickstart written in Kotlin.", Intent( this, - com.google.samples.quickstart.config.kotlin.MainActivity::class.java)) + com.google.samples.quickstart.config.kotlin.MainActivity::class.java)), + Choice( + "Compose", + "Run the Firebase Remote Config quickstart written in Compose.", + Intent( + this, + com.google.samples.quickstart.config.kotlin.MainComposeActivity::class.java)) ) } } diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt new file mode 100644 index 0000000000..a7a00d4111 --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -0,0 +1,111 @@ +package com.google.samples.quickstart.config.kotlin + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material.TopAppBar +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +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.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.google.samples.quickstart.config.R +import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme +//import com.google.samples.quickstart.config.ui.theme.ConfigTheme + + +class MainComposeActivity : ComponentActivity() { + private var startingText: String = "Fetching Config..." + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContent { + ConfigTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + MainAppView(remoteConfigDisplayText = startingText) + } + } + } + } +} + + +@Composable +fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ + Column(modifier, horizontalAlignment = Alignment.CenterHorizontally){ + AppNameBanner() + Spacer(modifier = Modifier.height(24.dp)) + + Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "") +// Spacer(modifier = Modifier.height(16.dp)) + + ConfigText(remoteConfigDisplayText = remoteConfigDisplayText) + Spacer(modifier = Modifier.height(160.dp)) + + ConfigButton() + } + +} + +@Composable +fun AppNameBanner(modifier: Modifier = Modifier){ + TopAppBar( + backgroundColor = colorResource(R.color.colorPrimary) + ) { + androidx.compose.material.Text( + text = stringResource(R.string.app_name), + style = androidx.compose.material.MaterialTheme.typography.h6, + textAlign = TextAlign.Center, + modifier = Modifier.padding(8.dp), + color = Color.White + ) + } +} + +@Composable +fun ConfigText(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ + Text( + text = remoteConfigDisplayText, + fontSize = 16.sp + ) +} + +@Composable +fun ConfigButton(modifier: Modifier = Modifier){ + Button( + colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), + onClick = { } //lambda for onClick action + ) { + Text( + text = stringResource(R.string.fetch_remote_welcome_message), + fontSize = 20.sp + ) + } +} + + +@Composable +fun Greeting(name: String) { + Text(text = "Hello $name!") +} + +@Preview(showBackground = true) +@Composable +fun DefaultPreview() { + ConfigTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt new file mode 100644 index 0000000000..4013fa1ef0 --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.google.samples.quickstart.config.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/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt new file mode 100644 index 0000000000..737f17a02e --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt @@ -0,0 +1,69 @@ +package com.google.samples.quickstart.config.kotlin.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.ViewCompat +import kotlin.text.Typography + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = FirebaseBlue, + secondary = FirebaseBannerBlue, + tertiary = 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 ConfigTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb() + ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme + } + } + + MaterialTheme( + colorScheme = colorScheme, + typography = com.google.samples.quickstart.config.kotlin.ui.theme.Typography, + content = content + ) +} \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt new file mode 100644 index 0000000000..5abde43e05 --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.google.samples.quickstart.config.kotlin.ui.theme + +import androidx.compose.material3.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( + bodyLarge = 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/config/app/src/main/res/values/strings.xml b/config/app/src/main/res/values/strings.xml index f03807996a..e4a81651d5 100644 --- a/config/app/src/main/res/values/strings.xml +++ b/config/app/src/main/res/values/strings.xml @@ -1,4 +1,5 @@ Firebase Remote Config - fetch remote welcome + Fetch Remote Welcome + MainComposeActivity diff --git a/config/build.gradle b/config/build.gradle index f9bdde250d..d53e8acfd0 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -1,6 +1,9 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { + ext { + compose_version = '1.2.0' + } repositories { mavenLocal() google() diff --git a/config/gradle.properties b/config/gradle.properties index aac7c9b461..29b531a1d1 100644 --- a/config/gradle.properties +++ b/config/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 From cfb04ecbbb3fb386ce306354004c016aff28320f Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Sat, 21 Jan 2023 14:38:13 -0600 Subject: [PATCH 02/19] Added Firebase Config Added Firebase Config functionality --- .../config/kotlin/FirebaseActivity.kt | 77 +++++++++++++++++++ .../config/kotlin/MainComposeActivity.kt | 38 +++++++-- 2 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt new file mode 100644 index 0000000000..65f438952c --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt @@ -0,0 +1,77 @@ +package com.google.samples.quickstart.config.kotlin + +import android.app.Activity +import android.content.Context +import android.util.Log +import android.widget.Toast +import com.google.android.gms.tasks.Task +import com.google.firebase.ktx.Firebase +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.ktx.get +import com.google.firebase.remoteconfig.ktx.remoteConfig +import com.google.firebase.remoteconfig.ktx.remoteConfigSettings +import com.google.samples.quickstart.config.R + +class FirebaseActivity { + companion object { + + private const val TAG = "FirebaseActivity" + + // Remote Config keys + private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase" + private const val WELCOME_MESSAGE_KEY = "welcome_message" + private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps" + + // init config + fun initializeConfig() : FirebaseRemoteConfig { + // Get Remote Config instance. + // [START get_remote_config_instance] + val remoteConfig = Firebase.remoteConfig + // [END get_remote_config_instance] + + // Create a Remote Config Setting to enable developer mode, which you can use to increase + // the number of fetches available per hour during development. Also use Remote Config + // Setting to set the minimum fetch interval. + // [START enable_dev_mode] + val configSettings = remoteConfigSettings { + minimumFetchIntervalInSeconds = 3600 + } + remoteConfig.setConfigSettingsAsync(configSettings) + // [END enable_dev_mode] + + // Set default Remote Config parameter values. An app uses the in-app default values, and + // when you need to adjust those defaults, you set an updated value for only the values you + // want to change in the Firebase console. See Best Practices in the README for more + // information. + // [START set_default_values] + remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) + // [END set_default_values] + return remoteConfig + } + + // fetch msg + + // Receives the remoteConfig to fetch a message + fun fetchConfig(activity : Activity, remoteConfig : FirebaseRemoteConfig) : String{ + + remoteConfig.fetchAndActivate() + .addOnCompleteListener(activity) { task -> + if (task.isSuccessful) { + val updated = task.result + Log.d(TAG, "Config params updated: $updated") + Toast.makeText(activity, "Fetch and activate succeeded", + Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(activity, "Fetch failed", + Toast.LENGTH_SHORT).show() + } + } + + return remoteConfig[WELCOME_MESSAGE_KEY].asString() + } + + + + + } +} \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index a7a00d4111..d6b9ea6625 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -18,16 +18,42 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme //import com.google.samples.quickstart.config.ui.theme.ConfigTheme class MainComposeActivity : ComponentActivity() { - private var startingText: String = "Fetching Config..." + private val startingText: String = "Welcome! Please fetch Config..." + private lateinit var displayText: String + private lateinit var remoteConfig: FirebaseRemoteConfig + private val buttonClickLambda = { configButtonOnClick() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + + //Initialize config and set starting text + remoteConfig = FirebaseActivity.initializeConfig() + displayText = startingText + + setContent { + ConfigTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + MainAppView(remoteConfigDisplayText = displayText, buttonClickEventMSGFetcher = buttonClickLambda) + } + } + } + } + + fun configButtonOnClick(){ + // Call the FirebaseActivity to fetch the message + displayText = FirebaseActivity.fetchConfig(this, remoteConfig) + setContent { ConfigTheme { // A surface container using the 'background' color from the theme @@ -35,7 +61,7 @@ class MainComposeActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - MainAppView(remoteConfigDisplayText = startingText) + MainAppView(remoteConfigDisplayText = displayText, buttonClickEventMSGFetcher = buttonClickLambda) } } } @@ -44,7 +70,7 @@ class MainComposeActivity : ComponentActivity() { @Composable -fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ +fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String, buttonClickEventMSGFetcher : () -> Unit = {}){ Column(modifier, horizontalAlignment = Alignment.CenterHorizontally){ AppNameBanner() Spacer(modifier = Modifier.height(24.dp)) @@ -55,7 +81,7 @@ fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ ConfigText(remoteConfigDisplayText = remoteConfigDisplayText) Spacer(modifier = Modifier.height(160.dp)) - ConfigButton() + ConfigButton(myClickEventMSGFetcher = buttonClickEventMSGFetcher) } } @@ -84,10 +110,10 @@ fun ConfigText(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ } @Composable -fun ConfigButton(modifier: Modifier = Modifier){ +fun ConfigButton(modifier: Modifier = Modifier, myClickEventMSGFetcher : () -> Unit = {}){ Button( colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { } //lambda for onClick action + onClick = { myClickEventMSGFetcher() } // Calls function from MainComposeActivity to change display text ) { Text( text = stringResource(R.string.fetch_remote_welcome_message), From 2b56c374995233f0c5e0869a7db4d7d7087dd3da Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Tue, 24 Jan 2023 22:02:38 -0600 Subject: [PATCH 03/19] Added initial PR changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added initial PR changes that Rosário had mentioned. --- config/app/build.gradle | 4 ++-- config/app/src/main/AndroidManifest.xml | 5 +---- .../config/kotlin/MainComposeActivity.kt | 14 -------------- config/app/src/main/res/values/strings.xml | 3 +-- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/config/app/build.gradle b/config/app/build.gradle index 4f629ae35c..bbbfb4e7f9 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -32,7 +32,7 @@ android { buildFeatures { viewBinding = true - compose true + compose = true } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -70,7 +70,7 @@ dependencies { // For an optimal experience using Remote Config, add the Firebase SDK // for Google Analytics. This is recommended, but not required. implementation 'com.google.firebase:firebase-analytics' - implementation 'androidx.compose.material3:material3:1.0.0-alpha02' + implementation 'androidx.compose.material3:material3:1.0.1' debugImplementation "androidx.fragment:fragment-testing:1.5.4" // Jetpack Compose diff --git a/config/app/src/main/AndroidManifest.xml b/config/app/src/main/AndroidManifest.xml index 0ab90089d6..ed2b8ff18a 100644 --- a/config/app/src/main/AndroidManifest.xml +++ b/config/app/src/main/AndroidManifest.xml @@ -9,11 +9,8 @@ - U ) } } - - -@Composable -fun Greeting(name: String) { - Text(text = "Hello $name!") -} - -@Preview(showBackground = true) -@Composable -fun DefaultPreview() { - ConfigTheme { - Greeting("Android") - } -} \ No newline at end of file diff --git a/config/app/src/main/res/values/strings.xml b/config/app/src/main/res/values/strings.xml index e4a81651d5..3f18f23cec 100644 --- a/config/app/src/main/res/values/strings.xml +++ b/config/app/src/main/res/values/strings.xml @@ -1,5 +1,4 @@ Firebase Remote Config - Fetch Remote Welcome - MainComposeActivity + Fetch remote welcome From 7e92fe5ca332d1a45c6ce078ed1dfb34eb9d0a1a Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Thu, 26 Jan 2023 12:42:01 -0600 Subject: [PATCH 04/19] Updated MainAppView Combined the text and button into the parent composable function --- .../config/kotlin/MainComposeActivity.kt | 39 +++++++------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 09f2462aa0..3b4e971227 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -76,12 +76,24 @@ fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String, Spacer(modifier = Modifier.height(24.dp)) Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "") -// Spacer(modifier = Modifier.height(16.dp)) - ConfigText(remoteConfigDisplayText = remoteConfigDisplayText) + // Text displayed + Text( + text = remoteConfigDisplayText, + fontSize = 16.sp + ) Spacer(modifier = Modifier.height(160.dp)) - ConfigButton(myClickEventMSGFetcher = buttonClickEventMSGFetcher) + // Button to fetch remote welcome + Button( + colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), + onClick = { buttonClickEventMSGFetcher() } // Calls function from MainComposeActivity to change display text + ) { + Text( + text = stringResource(R.string.fetch_remote_welcome_message), + fontSize = 20.sp + ) + } } } @@ -100,24 +112,3 @@ fun AppNameBanner(modifier: Modifier = Modifier){ ) } } - -@Composable -fun ConfigText(modifier: Modifier = Modifier, remoteConfigDisplayText: String){ - Text( - text = remoteConfigDisplayText, - fontSize = 16.sp - ) -} - -@Composable -fun ConfigButton(modifier: Modifier = Modifier, myClickEventMSGFetcher : () -> Unit = {}){ - Button( - colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { myClickEventMSGFetcher() } // Calls function from MainComposeActivity to change display text - ) { - Text( - text = stringResource(R.string.fetch_remote_welcome_message), - fontSize = 20.sp - ) - } -} From 17420d77231171fb77e0e3a2d3e1262677942fd5 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Thu, 26 Jan 2023 19:39:50 +0000 Subject: [PATCH 05/19] move Firebase logic to RemoteConfigViewModel --- config/app/build.gradle | 1 + .../config/kotlin/FirebaseActivity.kt | 77 ------------------- .../config/kotlin/MainComposeActivity.kt | 59 ++++++++------ .../config/kotlin/RemoteConfigViewModel.kt | 35 +++++++++ 4 files changed, 72 insertions(+), 100 deletions(-) delete mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt diff --git a/config/app/build.gradle b/config/app/build.gradle index bbbfb4e7f9..7b591eb544 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -78,6 +78,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.compose.ui:ui-test-junit4:$compose_version" androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt deleted file mode 100644 index 65f438952c..0000000000 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/FirebaseActivity.kt +++ /dev/null @@ -1,77 +0,0 @@ -package com.google.samples.quickstart.config.kotlin - -import android.app.Activity -import android.content.Context -import android.util.Log -import android.widget.Toast -import com.google.android.gms.tasks.Task -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.FirebaseRemoteConfig -import com.google.firebase.remoteconfig.ktx.get -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfigSettings -import com.google.samples.quickstart.config.R - -class FirebaseActivity { - companion object { - - private const val TAG = "FirebaseActivity" - - // Remote Config keys - private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase" - private const val WELCOME_MESSAGE_KEY = "welcome_message" - private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps" - - // init config - fun initializeConfig() : FirebaseRemoteConfig { - // Get Remote Config instance. - // [START get_remote_config_instance] - val remoteConfig = Firebase.remoteConfig - // [END get_remote_config_instance] - - // Create a Remote Config Setting to enable developer mode, which you can use to increase - // the number of fetches available per hour during development. Also use Remote Config - // Setting to set the minimum fetch interval. - // [START enable_dev_mode] - val configSettings = remoteConfigSettings { - minimumFetchIntervalInSeconds = 3600 - } - remoteConfig.setConfigSettingsAsync(configSettings) - // [END enable_dev_mode] - - // Set default Remote Config parameter values. An app uses the in-app default values, and - // when you need to adjust those defaults, you set an updated value for only the values you - // want to change in the Firebase console. See Best Practices in the README for more - // information. - // [START set_default_values] - remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) - // [END set_default_values] - return remoteConfig - } - - // fetch msg - - // Receives the remoteConfig to fetch a message - fun fetchConfig(activity : Activity, remoteConfig : FirebaseRemoteConfig) : String{ - - remoteConfig.fetchAndActivate() - .addOnCompleteListener(activity) { task -> - if (task.isSuccessful) { - val updated = task.result - Log.d(TAG, "Config params updated: $updated") - Toast.makeText(activity, "Fetch and activate succeeded", - Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(activity, "Fetch failed", - Toast.LENGTH_SHORT).show() - } - } - - return remoteConfig[WELCOME_MESSAGE_KEY].asString() - } - - - - - } -} \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 3b4e971227..7e2b86af0f 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.* import androidx.compose.material.TopAppBar import androidx.compose.material3.* import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -15,27 +17,25 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource 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.compose.ui.unit.sp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.firebase.ktx.Firebase import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.ktx.remoteConfig +import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme //import com.google.samples.quickstart.config.ui.theme.ConfigTheme class MainComposeActivity : ComponentActivity() { - private val startingText: String = "Welcome! Please fetch Config..." - private lateinit var displayText: String - private lateinit var remoteConfig: FirebaseRemoteConfig - private val buttonClickLambda = { configButtonOnClick() } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //Initialize config and set starting text - remoteConfig = FirebaseActivity.initializeConfig() - displayText = startingText + val remoteConfig = initializeConfig() setContent { ConfigTheme { @@ -44,33 +44,45 @@ class MainComposeActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - MainAppView(remoteConfigDisplayText = displayText, buttonClickEventMSGFetcher = buttonClickLambda) + MainAppView() } } } } - fun configButtonOnClick(){ - // Call the FirebaseActivity to fetch the message - displayText = FirebaseActivity.fetchConfig(this, remoteConfig) + private fun initializeConfig() : FirebaseRemoteConfig { + // Get Remote Config instance. + // [START get_remote_config_instance] + val remoteConfig = Firebase.remoteConfig + // [END get_remote_config_instance] - setContent { - ConfigTheme { - // A surface container using the 'background' color from the theme - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background - ) { - MainAppView(remoteConfigDisplayText = displayText, buttonClickEventMSGFetcher = buttonClickLambda) - } - } + // Create a Remote Config Setting to enable developer mode, which you can use to increase + // the number of fetches available per hour during development. Also use Remote Config + // Setting to set the minimum fetch interval. + // [START enable_dev_mode] + val configSettings = remoteConfigSettings { + minimumFetchIntervalInSeconds = 3600 } + remoteConfig.setConfigSettingsAsync(configSettings) + // [END enable_dev_mode] + + // Set default Remote Config parameter values. An app uses the in-app default values, and + // when you need to adjust those defaults, you set an updated value for only the values you + // want to change in the Firebase console. See Best Practices in the README for more + // information. + // [START set_default_values] + remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) + // [END set_default_values] + return remoteConfig } } @Composable -fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String, buttonClickEventMSGFetcher : () -> Unit = {}){ +fun MainAppView( + modifier: Modifier = Modifier, + remoteConfigViewModel: RemoteConfigViewModel = viewModel() +){ Column(modifier, horizontalAlignment = Alignment.CenterHorizontally){ AppNameBanner() Spacer(modifier = Modifier.height(24.dp)) @@ -78,6 +90,7 @@ fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String, Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "") // Text displayed + val remoteConfigDisplayText by remoteConfigViewModel.welcomeMessage.collectAsState() Text( text = remoteConfigDisplayText, fontSize = 16.sp @@ -87,7 +100,7 @@ fun MainAppView(modifier: Modifier = Modifier, remoteConfigDisplayText: String, // Button to fetch remote welcome Button( colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { buttonClickEventMSGFetcher() } // Calls function from MainComposeActivity to change display text + onClick = { remoteConfigViewModel.fetchConfig() } // Calls function from MainComposeActivity to change display text ) { Text( text = stringResource(R.string.fetch_remote_welcome_message), diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt new file mode 100644 index 0000000000..16a4133d82 --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt @@ -0,0 +1,35 @@ +package com.google.samples.quickstart.config.kotlin + +import android.util.Log +import androidx.lifecycle.ViewModel +import com.google.firebase.ktx.Firebase +import com.google.firebase.remoteconfig.FirebaseRemoteConfig +import com.google.firebase.remoteconfig.ktx.get +import com.google.firebase.remoteconfig.ktx.remoteConfig +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow + +class RemoteConfigViewModel( + private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig +) : ViewModel() { + private val _welcomeMessage = MutableStateFlow(remoteConfig[WELCOME_MESSAGE_KEY].asString()) + val welcomeMessage: StateFlow = _welcomeMessage + + fun fetchConfig() { + remoteConfig.fetchAndActivate() + .addOnCompleteListener { task -> + if (task.isSuccessful) { + val updated = task.result + Log.d(TAG, "Config params updated: $updated") + _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + } else { + _welcomeMessage.value = task.exception?.message ?: "Unknown Error" + } + } + } + + companion object { + const val TAG = "ConfigViewModel" + private const val WELCOME_MESSAGE_KEY = "welcome_message" + } +} \ No newline at end of file From 294918e5ca2dada8ea7e0dc74917439334eb69fa Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Thu, 26 Jan 2023 23:07:42 -0600 Subject: [PATCH 06/19] Updated imports Updated the MainComposeActivity.kt to remove the wildcard imports and replaced with the appropriate ones --- config/app/build.gradle | 2 +- .../quickstart/config/kotlin/MainComposeActivity.kt | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/config/app/build.gradle b/config/app/build.gradle index 7b591eb544..98fbf7e8c4 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -78,7 +78,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" + implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 7e2b86af0f..bbf6f3adfe 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -4,9 +4,17 @@ import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.Spacer import androidx.compose.material.TopAppBar -import androidx.compose.material3.* +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue @@ -26,7 +34,6 @@ import com.google.firebase.remoteconfig.ktx.remoteConfig import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme -//import com.google.samples.quickstart.config.ui.theme.ConfigTheme class MainComposeActivity : ComponentActivity() { From 5b2bf5934b3553e30fcbfdd26cb9fb9f6a6ab46f Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Fri, 27 Jan 2023 09:46:21 -0600 Subject: [PATCH 07/19] Corrected exceeded max line length error Corrected exceeded max line length error by putting the comment under the code. Corrected build.gradle code to have proper syntax --- config/app/build.gradle | 4 ++-- .../samples/quickstart/config/kotlin/MainComposeActivity.kt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/app/build.gradle b/config/app/build.gradle index 98fbf7e8c4..7c3bdd1137 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -19,13 +19,13 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { - useSupportLibrary true + useSupportLibrary = true } } buildTypes { release { - minifyEnabled true + minifyEnabled = true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index bbf6f3adfe..4e910511d2 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -107,7 +107,8 @@ fun MainAppView( // Button to fetch remote welcome Button( colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { remoteConfigViewModel.fetchConfig() } // Calls function from MainComposeActivity to change display text + onClick = { remoteConfigViewModel.fetchConfig() } + // Calls function from MainComposeActivity to change display text ) { Text( text = stringResource(R.string.fetch_remote_welcome_message), From f129dcc1b3be7a7e1b9dd56f191108eb30f0d0ee Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Fri, 27 Jan 2023 10:06:24 -0600 Subject: [PATCH 08/19] Updated MainComposeAcitvity.kt Updated MainComposeAcitvity.kt to correct lint error --- .../samples/quickstart/config/kotlin/MainComposeActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 4e910511d2..1169a6cacf 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -107,8 +107,10 @@ fun MainAppView( // Button to fetch remote welcome Button( colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { remoteConfigViewModel.fetchConfig() } - // Calls function from MainComposeActivity to change display text + onClick = { + // Fetch config and update the display text + remoteConfigViewModel.fetchConfig() + } ) { Text( text = stringResource(R.string.fetch_remote_welcome_message), From 903bea400043ba6a2660ceb069b508521ca5e66e Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 17:50:11 +0000 Subject: [PATCH 09/19] create RemoteConfigViewModel.Factory to inject VM dependencies A couples of things happened here: - Renamed `fetchConfig()` to `fetchRemoteConfig()` - Created ViewModel Factory to help inject VM dependencies - Moved FirebaseRemoteConfig initialization to the ViewModel (The UI now calls these methods when the screen is created, through a DisposableEffect) - The default value from the XML file is now shown when the screen is first shown --- .../config/kotlin/MainComposeActivity.kt | 67 ++++++++----------- .../config/kotlin/RemoteConfigViewModel.kt | 54 +++++++++++++-- 2 files changed, 77 insertions(+), 44 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 1169a6cacf..6401efabba 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -16,22 +16,23 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.viewmodel.compose.viewModel -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.FirebaseRemoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme @@ -40,10 +41,6 @@ class MainComposeActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - - //Initialize config and set starting text - val remoteConfig = initializeConfig() - setContent { ConfigTheme { // A surface container using the 'background' color from the theme @@ -56,41 +53,32 @@ class MainComposeActivity : ComponentActivity() { } } } - - private fun initializeConfig() : FirebaseRemoteConfig { - // Get Remote Config instance. - // [START get_remote_config_instance] - val remoteConfig = Firebase.remoteConfig - // [END get_remote_config_instance] - - // Create a Remote Config Setting to enable developer mode, which you can use to increase - // the number of fetches available per hour during development. Also use Remote Config - // Setting to set the minimum fetch interval. - // [START enable_dev_mode] - val configSettings = remoteConfigSettings { - minimumFetchIntervalInSeconds = 3600 - } - remoteConfig.setConfigSettingsAsync(configSettings) - // [END enable_dev_mode] - - // Set default Remote Config parameter values. An app uses the in-app default values, and - // when you need to adjust those defaults, you set an updated value for only the values you - // want to change in the Firebase console. See Best Practices in the README for more - // information. - // [START set_default_values] - remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) - // [END set_default_values] - return remoteConfig - } } @Composable fun MainAppView( modifier: Modifier = Modifier, - remoteConfigViewModel: RemoteConfigViewModel = viewModel() -){ - Column(modifier, horizontalAlignment = Alignment.CenterHorizontally){ + lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current, + remoteConfigViewModel: RemoteConfigViewModel = viewModel(factory = RemoteConfigViewModel.Factory) +) { + DisposableEffect(lifecycleOwner) { + val observer = LifecycleEventObserver { _, event -> + // Configure Firebase Remote Config when the screen is created + if (event == Lifecycle.Event.ON_CREATE) { + remoteConfigViewModel.enableDeveloperMode() + remoteConfigViewModel.setDefaultValues(R.xml.remote_config_defaults) + } + } + + lifecycleOwner.lifecycle.addObserver(observer) + + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + } + + Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { AppNameBanner() Spacer(modifier = Modifier.height(24.dp)) @@ -109,7 +97,7 @@ fun MainAppView( colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), onClick = { // Fetch config and update the display text - remoteConfigViewModel.fetchConfig() + remoteConfigViewModel.fetchRemoteConfig() } ) { Text( @@ -118,11 +106,10 @@ fun MainAppView( ) } } - } @Composable -fun AppNameBanner(modifier: Modifier = Modifier){ +fun AppNameBanner(modifier: Modifier = Modifier) { TopAppBar( backgroundColor = colorResource(R.color.colorPrimary) ) { diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt index 16a4133d82..3a16404c66 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt @@ -2,20 +2,51 @@ package com.google.samples.quickstart.config.kotlin 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.ktx.Firebase import com.google.firebase.remoteconfig.FirebaseRemoteConfig import com.google.firebase.remoteconfig.ktx.get import com.google.firebase.remoteconfig.ktx.remoteConfig +import com.google.firebase.remoteconfig.ktx.remoteConfigSettings import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.tasks.await class RemoteConfigViewModel( - private val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig + private val remoteConfig: FirebaseRemoteConfig ) : ViewModel() { - private val _welcomeMessage = MutableStateFlow(remoteConfig[WELCOME_MESSAGE_KEY].asString()) + private val _welcomeMessage = MutableStateFlow("Welcome...") val welcomeMessage: StateFlow = _welcomeMessage - fun fetchConfig() { + fun enableDeveloperMode() { + viewModelScope.launch { + // Create a Remote Config Setting to enable developer mode, which you can use to increase + // the number of fetches available per hour during development. Also use Remote Config + // Setting to set the minimum fetch interval. + val configSettings = remoteConfigSettings { + minimumFetchIntervalInSeconds = 3600 + } + remoteConfig.setConfigSettingsAsync(configSettings).await() + } + } + + fun setDefaultValues(defaultValuesXml: Int) { + viewModelScope.launch { + // Set default Remote Config parameter values. An app uses the in-app default values, and + // when you need to adjust those defaults, you set an updated value for only the values you + // want to change in the Firebase console. See Best Practices in the README for more + // information. + remoteConfig.setDefaultsAsync(defaultValuesXml).await() + + // Update the UI with the default parameter value for welcome message + _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + } + } + + fun fetchRemoteConfig() { remoteConfig.fetchAndActivate() .addOnCompleteListener { task -> if (task.isSuccessful) { @@ -23,13 +54,28 @@ class RemoteConfigViewModel( Log.d(TAG, "Config params updated: $updated") _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() } else { + Log.e(TAG, "There was an error fetching and activating your config") _welcomeMessage.value = task.exception?.message ?: "Unknown Error" } } } companion object { - const val TAG = "ConfigViewModel" + const val TAG = "RemoteConfigViewModel" private const val WELCOME_MESSAGE_KEY = "welcome_message" + + // 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 { + // Get Remote Config instance. + val remoteConfig = Firebase.remoteConfig + return RemoteConfigViewModel(remoteConfig) as T + } + } } } \ No newline at end of file From 63fe453c4e27ae504934d9cf2371bbf75d7a833d Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 17:59:55 +0000 Subject: [PATCH 10/19] use the same ViewModel in the Kotlin+XML Activity --- .../quickstart/config/kotlin/MainActivity.kt | 91 +++---------------- 1 file changed, 12 insertions(+), 79 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt index 90a38e3941..620ccd519a 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt @@ -1,99 +1,32 @@ package com.google.samples.quickstart.config.kotlin import android.os.Bundle -import android.util.Log -import android.widget.Toast +import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import com.google.firebase.ktx.Firebase -import com.google.firebase.remoteconfig.FirebaseRemoteConfig -import com.google.firebase.remoteconfig.ktx.get -import com.google.firebase.remoteconfig.ktx.remoteConfig -import com.google.firebase.remoteconfig.ktx.remoteConfigSettings +import androidx.lifecycle.lifecycleScope import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.databinding.ActivityMainBinding +import kotlinx.coroutines.launch class MainActivity : AppCompatActivity() { - - private lateinit var remoteConfig: FirebaseRemoteConfig private lateinit var binding: ActivityMainBinding + private val viewModel: RemoteConfigViewModel by viewModels { RemoteConfigViewModel.Factory } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - binding.fetchButton.setOnClickListener { fetchWelcome() } - - // Get Remote Config instance. - // [START get_remote_config_instance] - remoteConfig = Firebase.remoteConfig - // [END get_remote_config_instance] + binding.fetchButton.setOnClickListener { viewModel.fetchRemoteConfig() } - // Create a Remote Config Setting to enable developer mode, which you can use to increase - // the number of fetches available per hour during development. Also use Remote Config - // Setting to set the minimum fetch interval. - // [START enable_dev_mode] - val configSettings = remoteConfigSettings { - minimumFetchIntervalInSeconds = 3600 - } - remoteConfig.setConfigSettingsAsync(configSettings) - // [END enable_dev_mode] + viewModel.enableDeveloperMode() - // Set default Remote Config parameter values. An app uses the in-app default values, and - // when you need to adjust those defaults, you set an updated value for only the values you - // want to change in the Firebase console. See Best Practices in the README for more - // information. - // [START set_default_values] - remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults) - // [END set_default_values] + viewModel.setDefaultValues(R.xml.remote_config_defaults) - fetchWelcome() - } - - /** - * Fetch a welcome message from the Remote Config service, and then activate it. - */ - private fun fetchWelcome() { - binding.welcomeTextView.text = remoteConfig[LOADING_PHRASE_CONFIG_KEY].asString() - - // [START fetch_config_with_callback] - remoteConfig.fetchAndActivate() - .addOnCompleteListener(this) { task -> - if (task.isSuccessful) { - val updated = task.result - Log.d(TAG, "Config params updated: $updated") - Toast.makeText(this, "Fetch and activate succeeded", - Toast.LENGTH_SHORT).show() - } else { - Toast.makeText(this, "Fetch failed", - Toast.LENGTH_SHORT).show() - } - displayWelcomeMessage() - } - // [END fetch_config_with_callback] - } - - /** - * Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise, - * display a welcome message as fetched from welcome_message. - */ - // [START display_welcome_message] - private fun displayWelcomeMessage() { - // [START get_config_values] - val welcomeMessage = remoteConfig[WELCOME_MESSAGE_KEY].asString() - // [END get_config_values] - binding.welcomeTextView.isAllCaps = remoteConfig[WELCOME_MESSAGE_CAPS_KEY].asBoolean() - binding.welcomeTextView.text = welcomeMessage - } - - companion object { - - private const val TAG = "MainActivity" - - // Remote Config keys - private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase" - private const val WELCOME_MESSAGE_KEY = "welcome_message" - private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps" + lifecycleScope.launch { + viewModel.welcomeMessage.collect { welcomeMessage -> + binding.welcomeTextView.text = welcomeMessage + } + } } - // [END display_welcome_message] } From b2cc524a9161ad8d5d62e1c80696871c26ce8ba8 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 18:02:35 +0000 Subject: [PATCH 11/19] use Coroutines to fetch remote config instead of OnCompleteListener --- .../config/kotlin/RemoteConfigViewModel.kt | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt index 3a16404c66..4d3d84a3ca 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt @@ -47,17 +47,16 @@ class RemoteConfigViewModel( } fun fetchRemoteConfig() { - remoteConfig.fetchAndActivate() - .addOnCompleteListener { task -> - if (task.isSuccessful) { - val updated = task.result - Log.d(TAG, "Config params updated: $updated") - _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() - } else { - Log.e(TAG, "There was an error fetching and activating your config") - _welcomeMessage.value = task.exception?.message ?: "Unknown Error" - } + viewModelScope.launch { + try { + val updated = remoteConfig.fetchAndActivate().await() + Log.d(TAG, "Config params updated: $updated") + _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + } catch (e: Exception) { + Log.e(TAG, "There was an error fetching and activating your config") + _welcomeMessage.value = e.message ?: "Unknown Error" } + } } companion object { From 40a511a563b4addf3d1d7409742b8ba0bd2c2907 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 18:09:15 +0000 Subject: [PATCH 12/19] add all caps and loading phrase parameters --- .../quickstart/config/kotlin/MainActivity.kt | 6 +++++ .../config/kotlin/MainComposeActivity.kt | 10 +++++++-- .../config/kotlin/RemoteConfigViewModel.kt | 22 ++++++++++++++++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt index 620ccd519a..9b191c78ea 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainActivity.kt @@ -28,5 +28,11 @@ class MainActivity : AppCompatActivity() { binding.welcomeTextView.text = welcomeMessage } } + + lifecycleScope.launch { + viewModel.allCaps.collect { isWelcomeAllCaps -> + binding.welcomeTextView.isAllCaps = isWelcomeAllCaps + } + } } } diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 6401efabba..883a09194c 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -55,7 +55,6 @@ class MainComposeActivity : ComponentActivity() { } } - @Composable fun MainAppView( modifier: Modifier = Modifier, @@ -86,8 +85,15 @@ fun MainAppView( // Text displayed val remoteConfigDisplayText by remoteConfigViewModel.welcomeMessage.collectAsState() + + val allCaps by remoteConfigViewModel.allCaps.collectAsState() + Text( - text = remoteConfigDisplayText, + text = if (allCaps) { + remoteConfigDisplayText.uppercase() + } else { + remoteConfigDisplayText + }, fontSize = 16.sp ) Spacer(modifier = Modifier.height(160.dp)) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt index 4d3d84a3ca..957a00f8aa 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt @@ -21,6 +21,9 @@ class RemoteConfigViewModel( private val _welcomeMessage = MutableStateFlow("Welcome...") val welcomeMessage: StateFlow = _welcomeMessage + private val _allCaps = MutableStateFlow(false) + val allCaps: StateFlow = _allCaps + fun enableDeveloperMode() { viewModelScope.launch { // Create a Remote Config Setting to enable developer mode, which you can use to increase @@ -41,17 +44,21 @@ class RemoteConfigViewModel( // information. remoteConfig.setDefaultsAsync(defaultValuesXml).await() - // Update the UI with the default parameter value for welcome message - _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + // Update the UI with the default parameter values + updateUI() } } fun fetchRemoteConfig() { + _welcomeMessage.value = remoteConfig[LOADING_PHRASE_CONFIG_KEY].asString() + viewModelScope.launch { try { val updated = remoteConfig.fetchAndActivate().await() Log.d(TAG, "Config params updated: $updated") - _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + + // Update the UI with the fetched parameter values + updateUI() } catch (e: Exception) { Log.e(TAG, "There was an error fetching and activating your config") _welcomeMessage.value = e.message ?: "Unknown Error" @@ -59,9 +66,18 @@ class RemoteConfigViewModel( } } + private fun updateUI() { + _welcomeMessage.value = remoteConfig[WELCOME_MESSAGE_KEY].asString() + _allCaps.value = remoteConfig[WELCOME_MESSAGE_CAPS_KEY].asBoolean() + } + companion object { const val TAG = "RemoteConfigViewModel" + + // Remote Config keys + private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase" private const val WELCOME_MESSAGE_KEY = "welcome_message" + private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps" // Used to inject this ViewModel's dependencies // See also: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories From cbb697a56e7d55beddbc4844393259e3fc506c06 Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 18:21:39 +0000 Subject: [PATCH 13/19] delete snippets from java MainActivity --- .../samples/quickstart/config/java/MainActivity.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java b/config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java index e4c537568e..9143ad64e7 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java +++ b/config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java @@ -65,27 +65,21 @@ public void onClick(View v) { }); // Get Remote Config instance. - // [START get_remote_config_instance] mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance(); - // [END get_remote_config_instance] // Create a Remote Config Setting to enable developer mode, which you can use to increase // the number of fetches available per hour during development. Also use Remote Config // Setting to set the minimum fetch interval. - // [START enable_dev_mode] FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder() .setMinimumFetchIntervalInSeconds(3600) .build(); mFirebaseRemoteConfig.setConfigSettingsAsync(configSettings); - // [END enable_dev_mode] // Set default Remote Config parameter values. An app uses the in-app default values, and // when you need to adjust those defaults, you set an updated value for only the values you // want to change in the Firebase console. See Best Practices in the README for more // information. - // [START set_default_values] mFirebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults); - // [END set_default_values] fetchWelcome(); } @@ -96,7 +90,6 @@ public void onClick(View v) { private void fetchWelcome() { mWelcomeTextView.setText(mFirebaseRemoteConfig.getString(LOADING_PHRASE_CONFIG_KEY)); - // [START fetch_config_with_callback] mFirebaseRemoteConfig.fetchAndActivate() .addOnCompleteListener(this, new OnCompleteListener() { @Override @@ -114,18 +107,14 @@ public void onComplete(@NonNull Task task) { displayWelcomeMessage(); } }); - // [END fetch_config_with_callback] } /** * Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise, * display a welcome message as fetched from welcome_message. */ - // [START display_welcome_message] private void displayWelcomeMessage() { - // [START get_config_values] String welcomeMessage = mFirebaseRemoteConfig.getString(WELCOME_MESSAGE_KEY); - // [END get_config_values] if (mFirebaseRemoteConfig.getBoolean(WELCOME_MESSAGE_CAPS_KEY)) { mWelcomeTextView.setAllCaps(true); } else { @@ -133,5 +122,4 @@ private void displayWelcomeMessage() { } mWelcomeTextView.setText(welcomeMessage); } - // [END display_welcome_message] } From eacea0d6272b49a3a7db8948c0ed2b1c6f0849fc Mon Sep 17 00:00:00 2001 From: rosariopf Date: Fri, 27 Jan 2023 18:35:49 +0000 Subject: [PATCH 14/19] chore: update ktlint version --- build.gradle | 8 +++- .../quickstart/config/EntryChoiceActivity.kt | 42 +++++++++++-------- .../config/kotlin/MainComposeActivity.kt | 3 +- .../config/kotlin/RemoteConfigViewModel.kt | 2 +- .../config/kotlin/ui/theme/Color.kt | 6 +-- .../config/kotlin/ui/theme/Theme.kt | 2 +- .../quickstart/config/kotlin/ui/theme/Type.kt | 2 +- 7 files changed, 37 insertions(+), 28 deletions(-) diff --git a/build.gradle b/build.gradle index a302e22708..86337508f2 100644 --- a/build.gradle +++ b/build.gradle @@ -60,7 +60,11 @@ configurations { } dependencies { - ktlint "com.github.shyiko:ktlint:0.31.0" + ktlint ("com.pinterest:ktlint:0.48.2") { + attributes { + attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL)) + } + } } task("ktlint", type: JavaExec, group: "verification") { @@ -75,7 +79,7 @@ task("ktlint", type: JavaExec, group: "verification") { description = "Check Kotlin code style." classpath = configurations.ktlint - main = "com.github.shyiko.ktlint.Main" + mainClass.set("com.pinterest.ktlint.Main") args = [ "--format", "--android", diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt index 49a58074d2..47c0d5c45a 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt @@ -8,24 +8,30 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() { override fun getChoices(): List { return listOf( - Choice( - "Java", - "Run the Firebase Remote Config quickstart written in Java.", - Intent( - this, - com.google.samples.quickstart.config.java.MainActivity::class.java)), - Choice( - "Kotlin", - "Run the Firebase Remote Config quickstart written in Kotlin.", - Intent( - this, - com.google.samples.quickstart.config.kotlin.MainActivity::class.java)), - Choice( - "Compose", - "Run the Firebase Remote Config quickstart written in Compose.", - Intent( - this, - com.google.samples.quickstart.config.kotlin.MainComposeActivity::class.java)) + Choice( + "Java", + "Run the Firebase Remote Config quickstart written in Java.", + Intent( + this, + com.google.samples.quickstart.config.java.MainActivity::class.java + ) + ), + Choice( + "Kotlin", + "Run the Firebase Remote Config quickstart written in Kotlin.", + Intent( + this, + com.google.samples.quickstart.config.kotlin.MainActivity::class.java + ) + ), + Choice( + "Compose", + "Run the Firebase Remote Config quickstart written in Compose.", + Intent( + this, + com.google.samples.quickstart.config.kotlin.MainComposeActivity::class.java + ) + ) ) } } diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 883a09194c..adefd64933 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -5,10 +5,10 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.Spacer import androidx.compose.material.TopAppBar import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -36,7 +36,6 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme - class MainComposeActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt index 957a00f8aa..9f54bc7910 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt @@ -93,4 +93,4 @@ class RemoteConfigViewModel( } } } -} \ No newline at end of file +} diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt index 4013fa1ef0..ae14d722f3 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Color.kt @@ -6,6 +6,6 @@ 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 +val FirebaseBlue = Color(0xFF0288D1) // copied from colors.xml +val FirebaseBannerBlue = Color(0xFF039BE5) // copied from colors.xml +val FirebaseOrange = Color(0xFFFFA000) // copied from colors.xml diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt index 737f17a02e..96377a0178 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt @@ -66,4 +66,4 @@ fun ConfigTheme( typography = com.google.samples.quickstart.config.kotlin.ui.theme.Typography, content = content ) -} \ No newline at end of file +} diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt index 5abde43e05..5d155d74e1 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt @@ -31,4 +31,4 @@ val Typography = Typography( letterSpacing = 0.5.sp ) */ -) \ No newline at end of file +) From 4d5f607472f41bf4efca5be64fc2c428d0e04a98 Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Tue, 31 Jan 2023 18:31:35 -0600 Subject: [PATCH 15/19] Updated MainComposeActivity Restructured the UI by implementing Scaffold --- .../config/kotlin/MainComposeActivity.kt | 60 ++++++++++--------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index adefd64933..7527a269f6 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -54,6 +54,7 @@ class MainComposeActivity : ComponentActivity() { } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun MainAppView( modifier: Modifier = Modifier, @@ -76,41 +77,46 @@ fun MainAppView( } } - Column(modifier, horizontalAlignment = Alignment.CenterHorizontally) { + Scaffold(topBar = { AppNameBanner() - Spacer(modifier = Modifier.height(24.dp)) + }, content = { + Column(modifier = Modifier.padding(it).fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { + Spacer(modifier = Modifier.height(24.dp)) - Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "") + Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "") - // Text displayed - val remoteConfigDisplayText by remoteConfigViewModel.welcomeMessage.collectAsState() + // Text displayed + val remoteConfigDisplayText by remoteConfigViewModel.welcomeMessage.collectAsState() - val allCaps by remoteConfigViewModel.allCaps.collectAsState() + val allCaps by remoteConfigViewModel.allCaps.collectAsState() - Text( - text = if (allCaps) { - remoteConfigDisplayText.uppercase() - } else { - remoteConfigDisplayText - }, - fontSize = 16.sp - ) - Spacer(modifier = Modifier.height(160.dp)) - - // Button to fetch remote welcome - Button( - colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), - onClick = { - // Fetch config and update the display text - remoteConfigViewModel.fetchRemoteConfig() - } - ) { Text( - text = stringResource(R.string.fetch_remote_welcome_message), - fontSize = 20.sp + text = if (allCaps) { + remoteConfigDisplayText.uppercase() + } else { + remoteConfigDisplayText + }, + fontSize = 16.sp ) + Spacer(modifier = Modifier.height(160.dp)) + + // Button to fetch remote welcome + Button( + colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), + onClick = { + // Fetch config and update the display text + remoteConfigViewModel.fetchRemoteConfig() + } + ) { + Text( + text = stringResource(R.string.fetch_remote_welcome_message), + fontSize = 20.sp + ) + } } - } + }) + + } @Composable From d1274830c7c9fca4c06d860b8c24a5f41fc2b8c8 Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Tue, 31 Jan 2023 18:35:46 -0600 Subject: [PATCH 16/19] Added right imports Added scaffold and fillMaxWidth imports. Currently having issues with the Scaffold and the experimental wanting it to use wildcard statements --- .../samples/quickstart/config/kotlin/MainComposeActivity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 7527a269f6..093f5c3f02 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -9,10 +9,12 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.TopAppBar import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable From 73bcd0dd354500b71bb9ff281a663fea31109eea Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Mon, 6 Feb 2023 10:32:08 -0600 Subject: [PATCH 17/19] Migrated from Material 3 to Material 2 Migrated the code from Material 3 to 2. Also updated Gradle file to use Compose 1.3 --- config/app/build.gradle | 2 +- .../config/kotlin/MainComposeActivity.kt | 52 +++++++------- .../config/kotlin/ui/theme/Shape.kt | 11 +++ .../config/kotlin/ui/theme/Theme.kt | 68 +++++++------------ .../quickstart/config/kotlin/ui/theme/Type.kt | 4 +- config/build.gradle | 2 +- 6 files changed, 63 insertions(+), 76 deletions(-) create mode 100644 config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt diff --git a/config/app/build.gradle b/config/app/build.gradle index 7c3bdd1137..b53a787ced 100644 --- a/config/app/build.gradle +++ b/config/app/build.gradle @@ -70,7 +70,7 @@ dependencies { // For an optimal experience using Remote Config, add the Firebase SDK // for Google Analytics. This is recommended, but not required. implementation 'com.google.firebase:firebase-analytics' - implementation 'androidx.compose.material3:material3:1.0.1' + implementation 'androidx.compose.material:material:1.3.1' debugImplementation "androidx.fragment:fragment-testing:1.5.4" // Jetpack Compose diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 093f5c3f02..51d7241a9a 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -3,20 +3,23 @@ package com.google.samples.quickstart.config.kotlin import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height +import androidx.compose.foundation.Image import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.Spacer + +import androidx.compose.material.Colors +import androidx.compose.material.Scaffold import androidx.compose.material.TopAppBar -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface +import androidx.compose.material.Text + import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState @@ -47,7 +50,7 @@ class MainComposeActivity : ComponentActivity() { // A surface container using the 'background' color from the theme Surface( modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background + color = MaterialTheme.colors.background ) { MainAppView() } @@ -56,7 +59,6 @@ class MainComposeActivity : ComponentActivity() { } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun MainAppView( modifier: Modifier = Modifier, @@ -80,7 +82,17 @@ fun MainAppView( } Scaffold(topBar = { - AppNameBanner() + TopAppBar( + backgroundColor = colorResource(R.color.colorPrimary) + ) { + androidx.compose.material.Text( + text = stringResource(R.string.app_name), + style = androidx.compose.material.MaterialTheme.typography.h6, + textAlign = TextAlign.Center, + modifier = Modifier.padding(8.dp), + color = Color.White + ) + } }, content = { Column(modifier = Modifier.padding(it).fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { Spacer(modifier = Modifier.height(24.dp)) @@ -104,7 +116,7 @@ fun MainAppView( // Button to fetch remote welcome Button( - colors = ButtonDefaults.buttonColors(containerColor = colorResource(R.color.colorAccent)), + colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorAccent)), onClick = { // Fetch config and update the display text remoteConfigViewModel.fetchRemoteConfig() @@ -121,17 +133,3 @@ fun MainAppView( } -@Composable -fun AppNameBanner(modifier: Modifier = Modifier) { - TopAppBar( - backgroundColor = colorResource(R.color.colorPrimary) - ) { - androidx.compose.material.Text( - text = stringResource(R.string.app_name), - style = androidx.compose.material.MaterialTheme.typography.h6, - textAlign = TextAlign.Center, - modifier = Modifier.padding(8.dp), - color = Color.White - ) - } -} diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt new file mode 100644 index 0000000000..5b06f939bd --- /dev/null +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt @@ -0,0 +1,11 @@ +package com.google.samples.quickstart.config.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(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp) +) \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt index 96377a0178..c3157d1e61 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt @@ -1,69 +1,47 @@ package com.google.samples.quickstart.config.kotlin.ui.theme -import android.app.Activity -import android.os.Build import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme +import androidx.compose.material.MaterialTheme +import androidx.compose.material.darkColors +import androidx.compose.material.lightColors import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect -import androidx.compose.ui.graphics.toArgb -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalView -import androidx.core.view.ViewCompat -import kotlin.text.Typography -private val DarkColorScheme = darkColorScheme( +private val DarkColorPalette = darkColors( primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 + primaryVariant = PurpleGrey80, + secondary = Pink80 ) -private val LightColorScheme = lightColorScheme( - primary = FirebaseBlue, - secondary = FirebaseBannerBlue, - tertiary = FirebaseOrange +private val LightColorPalette = lightColors( + primary = Purple80, + primaryVariant = PurpleGrey80, + secondary = Pink80 /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), + background = Color.White, + surface = Color.White, onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), + onSecondary = Color.Black, + onBackground = Color.Black, + onSurface = Color.Black, */ ) @Composable fun ConfigTheme( darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, content: @Composable () -> Unit ) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - darkTheme -> DarkColorScheme - else -> LightColorScheme - } - val view = LocalView.current - if (!view.isInEditMode) { - SideEffect { - (view.context as Activity).window.statusBarColor = colorScheme.primary.toArgb() - ViewCompat.getWindowInsetsController(view)?.isAppearanceLightStatusBars = darkTheme - } + val colors = if (darkTheme) { + DarkColorPalette + } else { + LightColorPalette } MaterialTheme( - colorScheme = colorScheme, - typography = com.google.samples.quickstart.config.kotlin.ui.theme.Typography, + colors = colors, + typography = Typography, + shapes = Shapes, content = content ) -} +} \ No newline at end of file diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt index 5d155d74e1..7d8bc30dd7 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Type.kt @@ -1,6 +1,6 @@ package com.google.samples.quickstart.config.kotlin.ui.theme -import androidx.compose.material3.Typography +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 @@ -8,7 +8,7 @@ import androidx.compose.ui.unit.sp // Set of Material typography styles to start with val Typography = Typography( - bodyLarge = TextStyle( + body1 = TextStyle( fontFamily = FontFamily.Default, fontWeight = FontWeight.Normal, fontSize = 16.sp, diff --git a/config/build.gradle b/config/build.gradle index d53e8acfd0..4f8407c741 100644 --- a/config/build.gradle +++ b/config/build.gradle @@ -2,7 +2,7 @@ buildscript { ext { - compose_version = '1.2.0' + compose_version = '1.3.0' } repositories { mavenLocal() From a9330fd9487b53f564cb904a97e69f809f0b633b Mon Sep 17 00:00:00 2001 From: millandavid <71908868+millandavid@users.noreply.github.com> Date: Mon, 6 Feb 2023 14:07:30 -0600 Subject: [PATCH 18/19] Added snackbar Added snackbar when config button is pressed. --- .../config/kotlin/MainComposeActivity.kt | 22 ++++++++++++++++--- .../config/kotlin/ui/theme/Shape.kt | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 51d7241a9a..78f0a2600c 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.Spacer -import androidx.compose.material.Colors import androidx.compose.material.Scaffold import androidx.compose.material.TopAppBar import androidx.compose.material.Button @@ -19,11 +18,13 @@ import androidx.compose.material.ButtonDefaults import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.material.Text +import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -40,6 +41,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.viewmodel.compose.viewModel import com.google.samples.quickstart.config.R import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme +import kotlinx.coroutines.launch class MainComposeActivity : ComponentActivity() { @@ -81,7 +83,12 @@ fun MainAppView( } } - Scaffold(topBar = { + val scaffoldState = rememberScaffoldState() // this contains the `SnackbarHostState` + val coroutineScope = rememberCoroutineScope() + + Scaffold( + scaffoldState = scaffoldState, + topBar = { TopAppBar( backgroundColor = colorResource(R.color.colorPrimary) ) { @@ -120,16 +127,25 @@ fun MainAppView( onClick = { // Fetch config and update the display text remoteConfigViewModel.fetchRemoteConfig() + // Display Scaffold + coroutineScope.launch { // using the `coroutineScope` to `launch` showing the snackbar + // taking the `snackbarHostState` from the attached `scaffoldState` + val snackbarResult = scaffoldState.snackbarHostState.showSnackbar( + message = "Fetching remote message..." + ) + } } ) { Text( text = stringResource(R.string.fetch_remote_welcome_message), - fontSize = 20.sp + fontSize = 20.sp, + color = Color.White ) } } }) + } diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt index 5b06f939bd..1c1509ac47 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Shape.kt @@ -5,7 +5,7 @@ import androidx.compose.material.Shapes import androidx.compose.ui.unit.dp val Shapes = Shapes( - small = RoundedCornerShape(4.dp), + small = RoundedCornerShape(16.dp), medium = RoundedCornerShape(4.dp), large = RoundedCornerShape(0.dp) ) \ No newline at end of file From e540eab4a624bc3c2e700e1f41a67f846e575b0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ros=C3=A1rio=20Pereira=20Fernandes?= Date: Fri, 10 Feb 2023 15:33:30 +0000 Subject: [PATCH 19/19] androidx.compose.material.Text --> Text --- .../samples/quickstart/config/kotlin/MainComposeActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt index 78f0a2600c..30d9764d57 100644 --- a/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt +++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt @@ -92,7 +92,7 @@ fun MainAppView( TopAppBar( backgroundColor = colorResource(R.color.colorPrimary) ) { - androidx.compose.material.Text( + Text( text = stringResource(R.string.app_name), style = androidx.compose.material.MaterialTheme.typography.h6, textAlign = TextAlign.Center,