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/build.gradle b/config/app/build.gradle
index 17f01745ba..b53a787ced 100644
--- a/config/app/build.gradle
+++ b/config/app/build.gradle
@@ -12,23 +12,42 @@ 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 {
release {
- minifyEnabled true
+ minifyEnabled = true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
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,21 @@ 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.material:material:1.3.1'
+
+ 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'
+ 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'
- 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..ed2b8ff18a 100644
--- a/config/app/src/main/AndroidManifest.xml
+++ b/config/app/src/main/AndroidManifest.xml
@@ -5,20 +5,23 @@
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 +30,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..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,18 +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(
+ "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/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]
}
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..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
@@ -1,99 +1,38 @@
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"
+ lifecycleScope.launch {
+ viewModel.welcomeMessage.collect { welcomeMessage ->
+ binding.welcomeTextView.text = welcomeMessage
+ }
+ }
- // 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.allCaps.collect { isWelcomeAllCaps ->
+ binding.welcomeTextView.isAllCaps = isWelcomeAllCaps
+ }
+ }
}
- // [END display_welcome_message]
}
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..30d9764d57
--- /dev/null
+++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/MainComposeActivity.kt
@@ -0,0 +1,151 @@
+package com.google.samples.quickstart.config.kotlin
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.compose.foundation.layout.Column
+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.Spacer
+
+import androidx.compose.material.Scaffold
+import androidx.compose.material.TopAppBar
+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.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
+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.samples.quickstart.config.R
+import com.google.samples.quickstart.config.kotlin.ui.theme.ConfigTheme
+import kotlinx.coroutines.launch
+
+class MainComposeActivity : ComponentActivity() {
+
+ 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.colors.background
+ ) {
+ MainAppView()
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun MainAppView(
+ modifier: Modifier = Modifier,
+ 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)
+ }
+ }
+
+ val scaffoldState = rememberScaffoldState() // this contains the `SnackbarHostState`
+ val coroutineScope = rememberCoroutineScope()
+
+ Scaffold(
+ scaffoldState = scaffoldState,
+ topBar = {
+ TopAppBar(
+ backgroundColor = colorResource(R.color.colorPrimary)
+ ) {
+ 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))
+
+ Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "")
+
+ // Text displayed
+ val remoteConfigDisplayText by remoteConfigViewModel.welcomeMessage.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(backgroundColor = colorResource(R.color.colorAccent)),
+ 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,
+ color = Color.White
+ )
+ }
+ }
+ })
+
+
+
+}
+
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..9f54bc7910
--- /dev/null
+++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/RemoteConfigViewModel.kt
@@ -0,0 +1,96 @@
+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
+) : ViewModel() {
+ 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
+ // 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 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")
+
+ // 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"
+ }
+ }
+ }
+
+ 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
+ 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
+ }
+ }
+ }
+}
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..ae14d722f3
--- /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
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..1c1509ac47
--- /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(16.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
new file mode 100644
index 0000000000..c3157d1e61
--- /dev/null
+++ b/config/app/src/main/java/com/google/samples/quickstart/config/kotlin/ui/theme/Theme.kt
@@ -0,0 +1,47 @@
+package com.google.samples.quickstart.config.kotlin.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.darkColors
+import androidx.compose.material.lightColors
+import androidx.compose.runtime.Composable
+
+private val DarkColorPalette = darkColors(
+ primary = Purple80,
+ primaryVariant = PurpleGrey80,
+ secondary = Pink80
+)
+
+private val LightColorPalette = lightColors(
+ primary = Purple80,
+ primaryVariant = PurpleGrey80,
+ secondary = Pink80
+
+ /* Other default colors to override
+ background = Color.White,
+ surface = Color.White,
+ onPrimary = Color.White,
+ onSecondary = Color.Black,
+ onBackground = Color.Black,
+ onSurface = Color.Black,
+ */
+)
+
+@Composable
+fun ConfigTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable () -> Unit
+) {
+ val colors = if (darkTheme) {
+ DarkColorPalette
+ } else {
+ LightColorPalette
+ }
+
+ MaterialTheme(
+ colors = colors,
+ typography = Typography,
+ shapes = Shapes,
+ content = content
+ )
+}
\ No newline at end of file
diff --git a/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..7d8bc30dd7
--- /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.material.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ body1 = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
diff --git a/config/app/src/main/res/values/strings.xml b/config/app/src/main/res/values/strings.xml
index f03807996a..3f18f23cec 100644
--- a/config/app/src/main/res/values/strings.xml
+++ b/config/app/src/main/res/values/strings.xml
@@ -1,4 +1,4 @@
Firebase Remote Config
- fetch remote welcome
+ Fetch remote welcome
diff --git a/config/build.gradle b/config/build.gradle
index f9bdde250d..4f8407c741 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.3.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