Skip to content

Commit 531aae6

Browse files
Create Remote Config quickstart in Compose (#1450)
* Added compose Added compose as an option to use Firebase * Added Firebase Config Added Firebase Config functionality * Added initial PR changes Added initial PR changes that Rosário had mentioned. * Updated MainAppView Combined the text and button into the parent composable function * move Firebase logic to RemoteConfigViewModel * Updated imports Updated the MainComposeActivity.kt to remove the wildcard imports and replaced with the appropriate ones * 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 * Updated MainComposeAcitvity.kt Updated MainComposeAcitvity.kt to correct lint error * 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 * use the same ViewModel in the Kotlin+XML Activity * use Coroutines to fetch remote config instead of OnCompleteListener * add all caps and loading phrase parameters * delete snippets from java MainActivity * chore: update ktlint version * Updated MainComposeActivity Restructured the UI by implementing Scaffold * Added right imports Added scaffold and fillMaxWidth imports. Currently having issues with the Scaffold and the experimental wanting it to use wildcard statements * Migrated from Material 3 to Material 2 Migrated the code from Material 3 to 2. Also updated Gradle file to use Compose 1.3 * Added snackbar Added snackbar when config button is pressed. * androidx.compose.material.Text --> Text --------- Co-authored-by: rosariopf <[email protected]>
1 parent f5530cd commit 531aae6

File tree

15 files changed

+449
-118
lines changed

15 files changed

+449
-118
lines changed

build.gradle

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ configurations {
6060
}
6161

6262
dependencies {
63-
ktlint "com.github.shyiko:ktlint:0.31.0"
63+
ktlint ("com.pinterest:ktlint:0.48.2") {
64+
attributes {
65+
attribute(Bundling.BUNDLING_ATTRIBUTE, getObjects().named(Bundling, Bundling.EXTERNAL))
66+
}
67+
}
6468
}
6569

6670
task("ktlint", type: JavaExec, group: "verification") {
@@ -75,7 +79,7 @@ task("ktlint", type: JavaExec, group: "verification") {
7579

7680
description = "Check Kotlin code style."
7781
classpath = configurations.ktlint
78-
main = "com.github.shyiko.ktlint.Main"
82+
mainClass.set("com.pinterest.ktlint.Main")
7983
args = [
8084
"--format",
8185
"--android",

config/app/build.gradle

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,42 @@ android {
1212

1313
defaultConfig {
1414
applicationId "com.google.samples.quickstart.config"
15-
minSdkVersion 19
15+
minSdkVersion 21
1616
targetSdkVersion 33
1717
versionCode 1
1818
versionName "1.0"
1919

2020
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
21+
vectorDrawables {
22+
useSupportLibrary = true
23+
}
2124
}
2225

2326
buildTypes {
2427
release {
25-
minifyEnabled true
28+
minifyEnabled = true
2629
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
2730
}
2831
}
2932

3033
buildFeatures {
3134
viewBinding = true
35+
compose = true
36+
}
37+
compileOptions {
38+
sourceCompatibility JavaVersion.VERSION_1_8
39+
targetCompatibility JavaVersion.VERSION_1_8
40+
}
41+
kotlinOptions {
42+
jvmTarget = '1.8'
43+
}
44+
composeOptions {
45+
kotlinCompilerExtensionVersion '1.3.2'
46+
}
47+
packagingOptions {
48+
resources {
49+
excludes += '/META-INF/{AL2.0,LGPL2.1}'
50+
}
3251
}
3352
}
3453

@@ -37,6 +56,7 @@ dependencies {
3756
implementation project(":internal:chooserx")
3857

3958
implementation 'com.google.android.material:material:1.7.0'
59+
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
4060

4161
// Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom)
4262
implementation platform('com.google.firebase:firebase-bom:31.1.0')
@@ -50,9 +70,21 @@ dependencies {
5070
// For an optimal experience using Remote Config, add the Firebase SDK
5171
// for Google Analytics. This is recommended, but not required.
5272
implementation 'com.google.firebase:firebase-analytics'
73+
implementation 'androidx.compose.material:material:1.3.1'
74+
75+
debugImplementation "androidx.fragment:fragment-testing:1.5.4"
76+
// Jetpack Compose
77+
implementation "androidx.compose.ui:ui:$compose_version"
78+
implementation "androidx.compose.material:material:$compose_version"
79+
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
80+
implementation 'androidx.activity:activity-compose:1.5.1'
81+
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
82+
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
5383

5484
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
55-
androidTestImplementation 'androidx.test:rules:1.5.0'
56-
androidTestImplementation 'androidx.test:runner:1.5.1'
57-
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
85+
androidTestImplementation 'androidx.test:rules:1.4.0'
86+
androidTestImplementation 'androidx.test:runner:1.4.0'
87+
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
88+
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
89+
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
5890
}

config/app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,23 @@
55
android:allowBackup="true"
66
android:icon="@mipmap/ic_launcher"
77
android:label="@string/app_name"
8-
android:theme="@style/AppTheme" >
9-
8+
android:theme="@style/AppTheme">
9+
<activity
10+
android:name=".kotlin.MainComposeActivity"
11+
android:exported="false"
12+
android:label="@string/app_name"
13+
android:theme="@style/AppTheme">
14+
</activity>
1015
<activity
1116
android:name=".java.MainActivity"
1217
android:label="@string/app_name" />
13-
1418
<activity
1519
android:name=".kotlin.MainActivity"
1620
android:label="@string/app_name" />
17-
1821
<activity
1922
android:name=".EntryChoiceActivity"
20-
android:label="@string/app_name"
21-
android:exported="true">
23+
android:exported="true"
24+
android:label="@string/app_name">
2225
<intent-filter>
2326
<action android:name="android.intent.action.MAIN" />
2427

@@ -27,4 +30,4 @@
2730
</activity>
2831
</application>
2932

30-
</manifest>
33+
</manifest>

config/app/src/main/java/com/google/samples/quickstart/config/EntryChoiceActivity.kt

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,30 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() {
88

99
override fun getChoices(): List<Choice> {
1010
return listOf(
11-
Choice(
12-
"Java",
13-
"Run the Firebase Remote Config quickstart written in Java.",
14-
Intent(
15-
this,
16-
com.google.samples.quickstart.config.java.MainActivity::class.java)),
17-
Choice(
18-
"Kotlin",
19-
"Run the Firebase Remote Config quickstart written in Kotlin.",
20-
Intent(
21-
this,
22-
com.google.samples.quickstart.config.kotlin.MainActivity::class.java))
11+
Choice(
12+
"Java",
13+
"Run the Firebase Remote Config quickstart written in Java.",
14+
Intent(
15+
this,
16+
com.google.samples.quickstart.config.java.MainActivity::class.java
17+
)
18+
),
19+
Choice(
20+
"Kotlin",
21+
"Run the Firebase Remote Config quickstart written in Kotlin.",
22+
Intent(
23+
this,
24+
com.google.samples.quickstart.config.kotlin.MainActivity::class.java
25+
)
26+
),
27+
Choice(
28+
"Compose",
29+
"Run the Firebase Remote Config quickstart written in Compose.",
30+
Intent(
31+
this,
32+
com.google.samples.quickstart.config.kotlin.MainComposeActivity::class.java
33+
)
34+
)
2335
)
2436
}
2537
}

config/app/src/main/java/com/google/samples/quickstart/config/java/MainActivity.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,27 +65,21 @@ public void onClick(View v) {
6565
});
6666

6767
// Get Remote Config instance.
68-
// [START get_remote_config_instance]
6968
mFirebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
70-
// [END get_remote_config_instance]
7169

7270
// Create a Remote Config Setting to enable developer mode, which you can use to increase
7371
// the number of fetches available per hour during development. Also use Remote Config
7472
// Setting to set the minimum fetch interval.
75-
// [START enable_dev_mode]
7673
FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
7774
.setMinimumFetchIntervalInSeconds(3600)
7875
.build();
7976
mFirebaseRemoteConfig.setConfigSettingsAsync(configSettings);
80-
// [END enable_dev_mode]
8177

8278
// Set default Remote Config parameter values. An app uses the in-app default values, and
8379
// when you need to adjust those defaults, you set an updated value for only the values you
8480
// want to change in the Firebase console. See Best Practices in the README for more
8581
// information.
86-
// [START set_default_values]
8782
mFirebaseRemoteConfig.setDefaultsAsync(R.xml.remote_config_defaults);
88-
// [END set_default_values]
8983

9084
fetchWelcome();
9185
}
@@ -96,7 +90,6 @@ public void onClick(View v) {
9690
private void fetchWelcome() {
9791
mWelcomeTextView.setText(mFirebaseRemoteConfig.getString(LOADING_PHRASE_CONFIG_KEY));
9892

99-
// [START fetch_config_with_callback]
10093
mFirebaseRemoteConfig.fetchAndActivate()
10194
.addOnCompleteListener(this, new OnCompleteListener<Boolean>() {
10295
@Override
@@ -114,24 +107,19 @@ public void onComplete(@NonNull Task<Boolean> task) {
114107
displayWelcomeMessage();
115108
}
116109
});
117-
// [END fetch_config_with_callback]
118110
}
119111

120112
/**
121113
* Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise,
122114
* display a welcome message as fetched from welcome_message.
123115
*/
124-
// [START display_welcome_message]
125116
private void displayWelcomeMessage() {
126-
// [START get_config_values]
127117
String welcomeMessage = mFirebaseRemoteConfig.getString(WELCOME_MESSAGE_KEY);
128-
// [END get_config_values]
129118
if (mFirebaseRemoteConfig.getBoolean(WELCOME_MESSAGE_CAPS_KEY)) {
130119
mWelcomeTextView.setAllCaps(true);
131120
} else {
132121
mWelcomeTextView.setAllCaps(false);
133122
}
134123
mWelcomeTextView.setText(welcomeMessage);
135124
}
136-
// [END display_welcome_message]
137125
}
Lines changed: 17 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,38 @@
11
package com.google.samples.quickstart.config.kotlin
22

33
import android.os.Bundle
4-
import android.util.Log
5-
import android.widget.Toast
4+
import androidx.activity.viewModels
65
import androidx.appcompat.app.AppCompatActivity
7-
import com.google.firebase.ktx.Firebase
8-
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
9-
import com.google.firebase.remoteconfig.ktx.get
10-
import com.google.firebase.remoteconfig.ktx.remoteConfig
11-
import com.google.firebase.remoteconfig.ktx.remoteConfigSettings
6+
import androidx.lifecycle.lifecycleScope
127
import com.google.samples.quickstart.config.R
138
import com.google.samples.quickstart.config.databinding.ActivityMainBinding
9+
import kotlinx.coroutines.launch
1410

1511
class MainActivity : AppCompatActivity() {
16-
17-
private lateinit var remoteConfig: FirebaseRemoteConfig
1812
private lateinit var binding: ActivityMainBinding
13+
private val viewModel: RemoteConfigViewModel by viewModels { RemoteConfigViewModel.Factory }
1914

2015
override fun onCreate(savedInstanceState: Bundle?) {
2116
super.onCreate(savedInstanceState)
2217
binding = ActivityMainBinding.inflate(layoutInflater)
2318
setContentView(binding.root)
2419

25-
binding.fetchButton.setOnClickListener { fetchWelcome() }
26-
27-
// Get Remote Config instance.
28-
// [START get_remote_config_instance]
29-
remoteConfig = Firebase.remoteConfig
30-
// [END get_remote_config_instance]
20+
binding.fetchButton.setOnClickListener { viewModel.fetchRemoteConfig() }
3121

32-
// Create a Remote Config Setting to enable developer mode, which you can use to increase
33-
// the number of fetches available per hour during development. Also use Remote Config
34-
// Setting to set the minimum fetch interval.
35-
// [START enable_dev_mode]
36-
val configSettings = remoteConfigSettings {
37-
minimumFetchIntervalInSeconds = 3600
38-
}
39-
remoteConfig.setConfigSettingsAsync(configSettings)
40-
// [END enable_dev_mode]
22+
viewModel.enableDeveloperMode()
4123

42-
// Set default Remote Config parameter values. An app uses the in-app default values, and
43-
// when you need to adjust those defaults, you set an updated value for only the values you
44-
// want to change in the Firebase console. See Best Practices in the README for more
45-
// information.
46-
// [START set_default_values]
47-
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
48-
// [END set_default_values]
24+
viewModel.setDefaultValues(R.xml.remote_config_defaults)
4925

50-
fetchWelcome()
51-
}
52-
53-
/**
54-
* Fetch a welcome message from the Remote Config service, and then activate it.
55-
*/
56-
private fun fetchWelcome() {
57-
binding.welcomeTextView.text = remoteConfig[LOADING_PHRASE_CONFIG_KEY].asString()
58-
59-
// [START fetch_config_with_callback]
60-
remoteConfig.fetchAndActivate()
61-
.addOnCompleteListener(this) { task ->
62-
if (task.isSuccessful) {
63-
val updated = task.result
64-
Log.d(TAG, "Config params updated: $updated")
65-
Toast.makeText(this, "Fetch and activate succeeded",
66-
Toast.LENGTH_SHORT).show()
67-
} else {
68-
Toast.makeText(this, "Fetch failed",
69-
Toast.LENGTH_SHORT).show()
70-
}
71-
displayWelcomeMessage()
72-
}
73-
// [END fetch_config_with_callback]
74-
}
75-
76-
/**
77-
* Display a welcome message in all caps if welcome_message_caps is set to true. Otherwise,
78-
* display a welcome message as fetched from welcome_message.
79-
*/
80-
// [START display_welcome_message]
81-
private fun displayWelcomeMessage() {
82-
// [START get_config_values]
83-
val welcomeMessage = remoteConfig[WELCOME_MESSAGE_KEY].asString()
84-
// [END get_config_values]
85-
binding.welcomeTextView.isAllCaps = remoteConfig[WELCOME_MESSAGE_CAPS_KEY].asBoolean()
86-
binding.welcomeTextView.text = welcomeMessage
87-
}
88-
89-
companion object {
90-
91-
private const val TAG = "MainActivity"
26+
lifecycleScope.launch {
27+
viewModel.welcomeMessage.collect { welcomeMessage ->
28+
binding.welcomeTextView.text = welcomeMessage
29+
}
30+
}
9231

93-
// Remote Config keys
94-
private const val LOADING_PHRASE_CONFIG_KEY = "loading_phrase"
95-
private const val WELCOME_MESSAGE_KEY = "welcome_message"
96-
private const val WELCOME_MESSAGE_CAPS_KEY = "welcome_message_caps"
32+
lifecycleScope.launch {
33+
viewModel.allCaps.collect { isWelcomeAllCaps ->
34+
binding.welcomeTextView.isAllCaps = isWelcomeAllCaps
35+
}
36+
}
9737
}
98-
// [END display_welcome_message]
9938
}

0 commit comments

Comments
 (0)