diff --git a/admob/app/build.gradle b/admob/app/build.gradle
index 1a388abe50..41007b0a05 100644
--- a/admob/app/build.gradle
+++ b/admob/app/build.gradle
@@ -8,17 +8,20 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.samples.quickstart.admobexample'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.samples.quickstart.admobexample"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary true
+ }
}
buildTypes {
@@ -36,6 +39,17 @@ 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'
}
}
@@ -47,19 +61,30 @@ dependencies {
implementation 'androidx.browser:browser:1.0.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation 'com.google.android.gms:play-services-ads:21.3.0'
// Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom)
- implementation platform('com.google.firebase:firebase-bom:31.1.0')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// For an optimal experience using AdMob, add the Firebase SDK
// for Google Analytics. This is recommended, but not required.
implementation 'com.google.firebase:firebase-analytics'
debugImplementation "androidx.fragment:fragment-testing:1.5.4"
- 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'
+ // 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"
+
+ debugImplementation "androidx.fragment:fragment-testing:1.5.2"
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ 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/admob/app/src/main/AndroidManifest.xml b/admob/app/src/main/AndroidManifest.xml
index aeddd6ffc3..fdd24ea521 100644
--- a/admob/app/src/main/AndroidManifest.xml
+++ b/admob/app/src/main/AndroidManifest.xml
@@ -36,6 +36,7 @@
+
diff --git a/admob/app/src/main/java/com/google/samples/quickstart/admobexample/EntryChoiceActivity.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/EntryChoiceActivity.kt
index adc6fee47c..cc69a5f048 100644
--- a/admob/app/src/main/java/com/google/samples/quickstart/admobexample/EntryChoiceActivity.kt
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/EntryChoiceActivity.kt
@@ -12,11 +12,15 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() {
Choice(
"Java",
"Run the Firebase Admob quickstart written in Java.",
- Intent(this, MainActivity::class.java)),
+ Intent(this, com.google.samples.quickstart.admobexample.java.MainActivity::class.java)),
Choice(
"Kotlin",
"Run the Firebase Admob quickstart written in Kotlin.",
- Intent(this, com.google.samples.quickstart.admobexample.kotlin.MainActivity::class.java))
+ Intent(this, com.google.samples.quickstart.admobexample.kotlin.MainActivity::class.java)),
+ Choice(
+ "Compose",
+ "Run the Firebase Admob quickstart written in Compose.",
+ Intent(this, com.google.samples.quickstart.admobexample.kotlin.MainComposeActivity::class.java))
)
}
}
diff --git a/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/MainComposeActivity.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/MainComposeActivity.kt
new file mode 100644
index 0000000000..04511c0333
--- /dev/null
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/MainComposeActivity.kt
@@ -0,0 +1,207 @@
+package com.google.samples.quickstart.admobexample.kotlin
+
+import android.content.ContentValues.TAG
+import android.os.Bundle
+import android.util.Log
+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.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.material.Surface
+import androidx.compose.material.TopAppBar
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Scaffold
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonDefaults
+import androidx.compose.material.Text
+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.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.viewinterop.AndroidView
+import com.google.android.gms.ads.AdError
+import com.google.android.gms.ads.AdRequest
+import com.google.android.gms.ads.AdSize
+import com.google.android.gms.ads.AdView
+import com.google.android.gms.ads.FullScreenContentCallback
+import com.google.android.gms.ads.LoadAdError
+import com.google.android.gms.ads.MobileAds
+import com.google.samples.quickstart.admobexample.kotlin.ui.theme.AdmobTheme
+import com.google.samples.quickstart.admobexample.R
+import com.google.android.gms.ads.interstitial.InterstitialAd
+import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
+
+class MainComposeActivity : ComponentActivity() {
+ private var mInterstitialAd: InterstitialAd? = null
+ private lateinit var adUnitId: String //="ca-app-pub-3940256099942544/1033173712" //could be set to another id
+ private val buttonClickLambda = { displayNewInterstitial() }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ adUnitId = getString(R.string.interstitial_ad_unit_id)
+
+ setContent {
+ AdmobTheme {
+ //A surface container using the 'background' color from the theme
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colors.background
+ ) {
+ MainAppView( buttonClickEventAdLoader = buttonClickLambda ) // call Composable UI
+ }
+ }
+
+ initializeInterstitial()
+ }
+ }
+
+ private fun setInterstitialCallback() {
+
+
+ mInterstitialAd?.fullScreenContentCallback = object: FullScreenContentCallback() {
+ override fun onAdClicked() {
+ // Called when a click is recorded for an ad.
+ Log.d(TAG, "Ad was clicked.")
+ }
+
+ override fun onAdDismissedFullScreenContent() {
+ // Called when ad is dismissed.
+ Log.d(TAG, "Ad dismissed fullscreen content.")
+ mInterstitialAd = null
+ initializeInterstitial() // get a new ad
+ }
+
+ override fun onAdFailedToShowFullScreenContent(p0: AdError) {
+ // Called when ad fails to show.
+ Log.e(TAG, "Ad failed to show fullscreen content.")
+ mInterstitialAd = null
+ initializeInterstitial() // get a new ad
+ }
+
+ override fun onAdImpression() {
+ // Called when an impression is recorded for an ad.
+ Log.d(TAG, "Ad recorded an impression.")
+ }
+
+ override fun onAdShowedFullScreenContent() {
+ // Called when ad is shown.
+ Log.d(TAG, "Ad showed fullscreen content.")
+ }
+ }
+ }
+
+ private fun initializeInterstitial(){
+ MobileAds.initialize(this)
+ val adRequest = AdRequest.Builder().build()
+
+ InterstitialAd.load(this, adUnitId, adRequest, object : InterstitialAdLoadCallback() {
+ override fun onAdFailedToLoad(adError: LoadAdError) {
+ Log.d(TAG, adError.toString())
+ mInterstitialAd = null
+ }
+
+ override fun onAdLoaded(interstitialAd: InterstitialAd) {
+ Log.d(TAG, "Ad was loaded.")
+ mInterstitialAd = interstitialAd
+ }
+ })
+ }
+
+ fun displayNewInterstitial(){
+ if (mInterstitialAd != null) { // ad is available
+ setInterstitialCallback() // set the callback methods
+ mInterstitialAd?.show(this)
+ } else { // ad is not available
+ Log.d("TAG", "The interstitial ad wasn't ready yet.")
+ initializeInterstitial()
+ }
+ }
+
+
+}
+
+
+@Composable
+fun MainAppView(modifier: Modifier = Modifier, buttonClickEventAdLoader : () -> Unit = {}){
+ Scaffold(
+ topBar = { // top bar with app name
+ 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()
+ .fillMaxHeight(),
+
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+ Spacer(modifier = Modifier.height(24.dp))
+
+ Image(painter = painterResource(R.drawable.firebase_lockup_400), contentDescription = "")
+ Spacer(modifier = Modifier.height(160.dp))
+ Button(
+ colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorAccent)),
+ onClick = { buttonClickEventAdLoader() } //lambda for onClick action
+ ) {
+ Text(
+ text = stringResource(R.string.interstitial_button_text),
+ fontSize = 24.sp,
+ color = Color.White
+ )
+ }
+
+ }
+ },
+ bottomBar = { // keeps the banner ad at the bottom!
+ AdvertBanner()
+ }
+ )
+
+}
+
+
+@Composable
+fun AdvertBanner(modifier: Modifier = Modifier) { // banner advert
+
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ ) {
+ AndroidView(
+ modifier = modifier.fillMaxWidth(),
+ factory = { context ->
+ AdView(context).apply {
+ setAdSize(AdSize.BANNER)
+ adUnitId = context.getString(R.string.banner_ad_unit_id)
+ loadAd(AdRequest.Builder().build())
+ }
+ }
+ )
+ }
+
+}
diff --git a/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Color.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Color.kt
new file mode 100644
index 0000000000..ca187c6eeb
--- /dev/null
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Color.kt
@@ -0,0 +1,13 @@
+package com.google.samples.quickstart.admobexample.kotlin.ui.theme
+
+import androidx.compose.ui.graphics.Color
+import com.google.samples.quickstart.admobexample.R
+
+val Purple80 = Color(0xFFD0BCFF)
+val PurpleGrey80 = Color(0xFFCCC2DC)
+val Pink80 = Color(0xFFEFB8C8)
+
+// self-defined light-mode colour scheme
+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/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Shape.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Shape.kt
new file mode 100644
index 0000000000..cb1986dc6e
--- /dev/null
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Shape.kt
@@ -0,0 +1,11 @@
+package com.google.samples.quickstart.admobexample.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/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Theme.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Theme.kt
new file mode 100644
index 0000000000..2ae9d75d42
--- /dev/null
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Theme.kt
@@ -0,0 +1,49 @@
+package com.google.samples.quickstart.admobexample.kotlin.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.darkColors
+import androidx.compose.material.lightColors
+import androidx.compose.runtime.Composable
+
+private val DarkColorPalette = darkColors(
+ primary = Purple80,
+ primaryVariant = PurpleGrey80,
+ secondary = Pink80
+)
+
+private val LightColorPalette = lightColors(
+ primary = FirebaseBlue,
+ primaryVariant = FirebaseBannerBlue,
+ secondary = FirebaseOrange
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun AdmobTheme(
+ darkTheme: Boolean = isSystemInDarkTheme(),
+ content: @Composable () -> Unit
+) {
+ val colors = if (darkTheme) {
+ DarkColorPalette
+ } else {
+ LightColorPalette
+ }
+
+ MaterialTheme(
+ colors = colors,
+ typography = Typography,
+ shapes = Shapes,
+ content = content
+ )
+}
+
diff --git a/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Type.kt b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Type.kt
new file mode 100644
index 0000000000..d4b748c801
--- /dev/null
+++ b/admob/app/src/main/java/com/google/samples/quickstart/admobexample/kotlin/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.google.samples.quickstart.admobexample.kotlin.ui.theme
+
+import androidx.compose.material.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ body1 = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/admob/build.gradle b/admob/build.gradle
index 264bea7c6f..d577ca24d5 100644
--- a/admob/build.gradle
+++ b/admob/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()
@@ -9,7 +12,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/analytics/app/build.gradle b/analytics/app/build.gradle
index f4c2adbf3c..53a4704f25 100644
--- a/analytics/app/build.gradle
+++ b/analytics/app/build.gradle
@@ -8,16 +8,19 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.firebase.quickstart.analytics'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.quickstart.analytics"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
multiDexEnabled true
+ 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}'
+ }
}
}
@@ -41,9 +60,10 @@ dependencies {
implementation "androidx.preference:preference-ktx:1.2.0"
// Needed to override the version used by preference-ktx
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
+ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Analytics (Java)
implementation 'com.google.firebase:firebase-analytics'
@@ -51,8 +71,17 @@ dependencies {
// Firebase Analytics (Kotlin)
implementation 'com.google.firebase:firebase-analytics-ktx'
- 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'
+ // 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.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/analytics/build.gradle b/analytics/build.gradle
index 904edcd299..219cc10cf3 100644
--- a/analytics/build.gradle
+++ b/analytics/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/appdistribution/app/build.gradle b/appdistribution/app/build.gradle
index d0f7200f88..cb4c85c269 100644
--- a/appdistribution/app/build.gradle
+++ b/appdistribution/app/build.gradle
@@ -6,15 +6,18 @@ plugins {
android {
namespace 'com.google.firebase.appdistributionquickstart'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.appdistributionquickstart"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -28,6 +31,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}'
+ }
}
lint {
warning 'InvalidPackage'
@@ -41,9 +60,10 @@ dependencies {
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.multidex:multidex:2.0.1'
+ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// ADD the SDK to the "prerelease" variant only (example)
implementation 'com.google.firebase:firebase-appdistribution-ktx:16.0.0-beta01'
@@ -52,8 +72,17 @@ dependencies {
// for Google Analytics. This is recommended, but not required.
implementation 'com.google.firebase:firebase-analytics'
- androidTestImplementation 'androidx.test:runner:1.5.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
- androidTestImplementation 'androidx.test:rules:1.5.0'
+ // 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.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/appdistribution/build.gradle b/appdistribution/build.gradle
index 9332ee6330..64c31555c4 100644
--- a/appdistribution/build.gradle
+++ b/appdistribution/build.gradle
@@ -10,7 +10,7 @@ buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.android.tools.build:gradle:7.3.1'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/auth/app/build.gradle b/auth/app/build.gradle
index c90259eac5..497f109737 100644
--- a/auth/app/build.gradle
+++ b/auth/app/build.gradle
@@ -13,11 +13,14 @@ android {
defaultConfig {
applicationId "com.google.firebase.quickstart.auth"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -28,13 +31,24 @@ android {
}
}
- compileOptions {
- sourceCompatibility 1.8
- targetCompatibility 1.8
- }
-
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}'
+ }
}
}
@@ -49,9 +63,17 @@ dependencies {
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
+
+ // 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'
// Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom)
- implementation platform('com.google.firebase:firebase-bom:31.1.0')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Authentication (Java)
implementation 'com.google.firebase:firebase-auth'
@@ -60,7 +82,7 @@ dependencies {
implementation 'com.google.firebase:firebase-auth-ktx'
// Google Identity Services SDK (only required for Auth with Google)
- implementation 'com.google.android.gms:play-services-auth:20.4.0'
+ implementation 'com.google.android.gms:play-services-auth:20.3.0'
// Firebase UI
// Used in FirebaseUIActivity.
@@ -71,7 +93,10 @@ dependencies {
implementation 'com.facebook.android:facebook-login:13.2.0'
implementation 'androidx.browser:browser:1.0.0'
- 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.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/auth/build.gradle b/auth/build.gradle
index 8d0a48998d..480ec3bab7 100644
--- a/auth/build.gradle
+++ b/auth/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/build.gradle b/build.gradle
index ee2372acf8..86337508f2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,4 +1,7 @@
buildscript {
+ ext {
+ compose_version = '1.2.1'
+ }
repositories {
google()
mavenCentral()
@@ -6,7 +9,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:perf-plugin:1.4.2'
@@ -57,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") {
@@ -72,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 98de3b7f07..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()
@@ -9,7 +12,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
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
diff --git a/crash/app/build.gradle b/crash/app/build.gradle
index 951e3acca1..daf6e7d972 100644
--- a/crash/app/build.gradle
+++ b/crash/app/build.gradle
@@ -9,14 +9,17 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.samples.quickstart.crash'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.samples.quickstart.crash"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -34,6 +37,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}'
+ }
}
}
@@ -42,9 +61,11 @@ dependencies {
implementation project(":internal:chooserx")
implementation 'com.google.android.material:material:1.7.0'
implementation "androidx.activity:activity-ktx:1.6.1"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
+ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Crashlytics (Kotlin)
implementation 'com.google.firebase:firebase-crashlytics-ktx'
@@ -56,9 +77,18 @@ dependencies {
// For use in the CustomKeySamples -- for testing Google Api Availability.
implementation 'com.google.android.gms:play-services-base:18.1.0'
+ // 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'
+
testImplementation 'junit:junit:4.13.2'
- 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.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/crash/build.gradle b/crash/build.gradle
index b482c29d2e..253a0e83f0 100644
--- a/crash/build.gradle
+++ b/crash/build.gradle
@@ -10,7 +10,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.2'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/database/app/build.gradle b/database/app/build.gradle
index 358bc33528..57305efb97 100644
--- a/database/app/build.gradle
+++ b/database/app/build.gradle
@@ -8,15 +8,18 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.firebase.quickstart.database'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.quickstart.database"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -30,6 +33,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}'
+ }
}
}
@@ -42,9 +61,11 @@ dependencies {
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1"
+ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Realtime Database (Java)
implementation 'com.google.firebase:firebase-database'
@@ -60,11 +81,20 @@ dependencies {
implementation 'com.firebaseui:firebase-ui-database:8.0.2'
+ // 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'
+
// Needed to fix a dependency conflict with FirebaseUI'
implementation 'androidx.arch.core:core-runtime:2.1.0'
testImplementation 'junit:junit:4.13.2'
- 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.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/database/build.gradle b/database/build.gradle
index 07766d813c..1554d788ed 100644
--- a/database/build.gradle
+++ b/database/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/dynamiclinks/app/build.gradle b/dynamiclinks/app/build.gradle
index 44ef9afd29..879444de1d 100644
--- a/dynamiclinks/app/build.gradle
+++ b/dynamiclinks/app/build.gradle
@@ -8,16 +8,19 @@ check.dependsOn 'assembleMainFlavorDebugAndroidTest'
android {
namespace 'com.google.firebase.quickstart.deeplinks'
- compileSdkVersion 33
+ compileSdk 33
flavorDimensions "irrelevant"
defaultConfig {
applicationId "com.google.firebase.quickstart.deeplinks"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -42,6 +45,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}'
+ }
}
}
@@ -50,9 +69,10 @@ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Dynamic Links (Java)
implementation 'com.google.firebase:firebase-dynamic-links'
@@ -64,8 +84,18 @@ dependencies {
// for Google Analytics. This is recommended, but not required.
implementation 'com.google.firebase:firebase-analytics'
- 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'
+ // 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.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/dynamiclinks/app/src/main/AndroidManifest.xml b/dynamiclinks/app/src/main/AndroidManifest.xml
index 615a7f5e9b..b22caa9f63 100644
--- a/dynamiclinks/app/src/main/AndroidManifest.xml
+++ b/dynamiclinks/app/src/main/AndroidManifest.xml
@@ -19,7 +19,6 @@
-
@@ -28,7 +27,6 @@
android:host="example.com"
android:scheme="https"/>
-
+
+
+
+
+
+
+
+
+
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/EntryChoiceActivity.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/EntryChoiceActivity.kt
index bf71091a90..d2cc39708f 100644
--- a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/EntryChoiceActivity.kt
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/EntryChoiceActivity.kt
@@ -15,7 +15,11 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() {
Choice(
"Kotlin",
"Run the Firebase Dynamic Links quickstart written in Kotlin.",
- Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainActivity::class.java))
+ Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainActivity::class.java)),
+ Choice(
+ "Compose",
+ "Run the Firebase Dynamic Links quickstart written in Compose.",
+ Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainComposeActivity::class.java))
)
}
}
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/java/MainActivity.java b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/java/MainActivity.java
index bde97fc687..3758392f62 100644
--- a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/java/MainActivity.java
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/java/MainActivity.java
@@ -46,10 +46,8 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String DEEP_LINK_URL = "https://example.com/deeplinks";
- // [START on_create]
@Override
protected void onCreate(Bundle savedInstanceState) {
- // [START_EXCLUDE]
super.onCreate(savedInstanceState);
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
@@ -89,9 +87,7 @@ public void onClick(View v) {
buildShortLinkFromParams(deepLink, 0);
}
});
- // [END_EXCLUDE]
- // [START get_deep_link]
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener() {
@@ -109,7 +105,6 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
// account.
// ...
- // [START_EXCLUDE]
// Display deep link in the UI
if (deepLink != null) {
Snackbar.make(findViewById(android.R.id.content),
@@ -119,7 +114,6 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
} else {
Log.d(TAG, "getDynamicLink: no link found");
}
- // [END_EXCLUDE]
}
})
.addOnFailureListener(this, new OnFailureListener() {
@@ -128,9 +122,7 @@ public void onFailure(@NonNull Exception e) {
Log.w(TAG, "getDynamicLink:onFailure", e);
}
});
- // [END get_deep_link]
}
- // [END on_create]
/**
* Build a Firebase Dynamic Link.
@@ -152,7 +144,6 @@ public Uri buildDeepLink(@NonNull Uri deepLink, int minVersion) {
// * URI prefix (required)
// * Android Parameters (required)
// * Deep link
- // [START build_dynamic_link]
DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance()
.createDynamicLink()
.setDomainUriPrefix(uriPrefix)
@@ -163,7 +154,6 @@ public Uri buildDeepLink(@NonNull Uri deepLink, int minVersion) {
// Build the dynamic link
DynamicLink link = builder.buildDynamicLink();
- // [END build_dynamic_link]
// Return the dynamic link as a URI
return link.getUri();
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/DynamicLinksViewModel.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/DynamicLinksViewModel.kt
new file mode 100644
index 0000000000..f3031fd419
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/DynamicLinksViewModel.kt
@@ -0,0 +1,143 @@
+package com.google.firebase.quickstart.deeplinks.kotlin
+
+import android.content.Intent
+import android.net.Uri
+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.dynamiclinks.FirebaseDynamicLinks
+import com.google.firebase.dynamiclinks.PendingDynamicLinkData
+import com.google.firebase.dynamiclinks.ktx.androidParameters
+import com.google.firebase.dynamiclinks.ktx.dynamicLink
+import com.google.firebase.dynamiclinks.ktx.dynamicLinks
+import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
+import com.google.firebase.ktx.Firebase
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.tasks.await
+
+class DynamicLinksViewModel(
+ private val dynamicLinks: FirebaseDynamicLinks
+): ViewModel() {
+
+ private val _deepLink = MutableStateFlow("")
+ val deepLink: StateFlow = _deepLink
+
+ private val _shortLink = MutableStateFlow("")
+ val shortLink: StateFlow = _shortLink
+
+ private val _validUriPrefix = MutableStateFlow(true)
+ val validUriPrefix: StateFlow = _validUriPrefix
+
+ fun getDynamicLink(intent: Intent) {
+ viewModelScope.launch {
+ try {
+ val pendingDynamicLinkData: PendingDynamicLinkData = dynamicLinks
+ .getDynamicLink(intent)
+ .await()
+
+ val deepLink: Uri? = pendingDynamicLinkData.link
+
+ // Handle the deep link. For example, open the linked
+ // content, or apply promotional credit to the user's
+ // account.
+ // ...
+
+ // Display deep link in the UI
+ if (deepLink != null) {
+ _deepLink.value = deepLink.toString()
+ } else {
+ Log.d(TAG, "getDynamicLink: no link found")
+ }
+ } catch (e: Exception) {
+ Log.w(TAG, "getDynamicLink:onFailure", e)
+ }
+ }
+ }
+
+
+ /**
+ * Build a Firebase Dynamic Link.
+ * https://firebase.google.com/docs/dynamic-links/android/create#create-a-dynamic-link-from-parameters
+ *
+ * @param deepLink the deep link your app will open. This link must be a valid URL and use the
+ * HTTP or HTTPS scheme.
+ * @param minVersion the `versionCode` of the minimum version of your app that can open
+ * the deep link. If the installed app is an older version, the user is taken
+ * to the Play store to upgrade the app. Pass 0 if you do not
+ * require a minimum version.
+ * @return a [Uri] representing a properly formed deep link.
+ */
+// @VisibleForTesting
+ fun buildDeepLink(uriPrefix: String, deepLink: Uri, minVersion: Int): Uri {
+ // Set dynamic link parameters:
+ // * URI prefix (required)
+ // * Android Parameters (required)
+ // * Deep link
+ // Build the dynamic link
+ val link = Firebase.dynamicLinks.dynamicLink {
+ domainUriPrefix = uriPrefix
+ androidParameters {
+ minimumVersion = minVersion
+ }
+ link = deepLink
+ }
+
+ // Return the dynamic link as a URI
+ return link.uri
+ }
+
+// @VisibleForTesting
+ fun buildShortLinkFromParams(uriPrefix: String, deepLink: Uri, minVersion: Int) {
+ // Set dynamic link parameters:
+ // * URI prefix (required)
+ // * Android Parameters (required)
+ // * Deep link
+
+ try {
+ viewModelScope.launch {
+ val shortDynamicLinks = Firebase.dynamicLinks.shortLinkAsync {
+ link = deepLink
+ domainUriPrefix = uriPrefix
+ androidParameters {
+ minimumVersion = minVersion
+ }
+ }.await()
+
+ val shortLinks = shortDynamicLinks.shortLink
+ // val flowChartLink = shortDynamicLinks.previewLink
+
+ _shortLink.value = shortLinks.toString()
+ }
+ } catch (e: Exception) {
+ Log.e(TAG, e.toString())
+ }
+ }
+
+ fun validateAppCode(uriPrefix: String) {
+ if (uriPrefix.contains("YOUR_APP")) {
+ _validUriPrefix.value = false
+ }
+ }
+
+ companion object {
+ const val TAG = "DynamicLinksViewModel"
+
+ // 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 dynamicLinks = Firebase.dynamicLinks
+ return DynamicLinksViewModel(dynamicLinks) as T
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainActivity.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainActivity.kt
index fb4e50ec79..33170baa4e 100644
--- a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainActivity.kt
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainActivity.kt
@@ -3,143 +3,83 @@ package com.google.firebase.quickstart.deeplinks.kotlin
import android.content.Intent
import android.net.Uri
import android.os.Bundle
-import androidx.annotation.VisibleForTesting
-import com.google.android.material.snackbar.Snackbar
+import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
-import android.util.Log
-import android.widget.TextView
-import com.google.firebase.dynamiclinks.PendingDynamicLinkData
-import com.google.firebase.dynamiclinks.ktx.androidParameters
-import com.google.firebase.dynamiclinks.ktx.dynamicLink
-import com.google.firebase.dynamiclinks.ktx.dynamicLinks
-import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
-import com.google.firebase.dynamiclinks.ktx.component1
-import com.google.firebase.dynamiclinks.ktx.component2
-import com.google.firebase.ktx.Firebase
+import androidx.lifecycle.lifecycleScope
+import com.google.android.material.snackbar.Snackbar
import com.google.firebase.quickstart.deeplinks.R
import com.google.firebase.quickstart.deeplinks.databinding.ActivityMainBinding
+import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
- // [START on_create]
+ private val viewModel: DynamicLinksViewModel by viewModels { DynamicLinksViewModel.Factory }
+
override fun onCreate(savedInstanceState: Bundle?) {
- // [START_EXCLUDE]
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val linkSendTextView = binding.linkViewSend
val linkReceiveTextView = binding.linkViewReceive
+ val shortLinkTextView = binding.shortLinkViewSend
+
+ val uriPrefix = getString(R.string.dynamic_links_uri_prefix)
// Validate that the developer has set the app code.
- validateAppCode()
+ viewModel.validateAppCode(uriPrefix)
// Create a deep link and display it in the UI
- val newDeepLink = buildDeepLink(Uri.parse(DEEP_LINK_URL), 0)
+
+ val newDeepLink = viewModel.buildDeepLink(uriPrefix, Uri.parse(DEEP_LINK_URL), 0)
linkSendTextView.text = newDeepLink.toString()
// Share button click listener
binding.buttonShare.setOnClickListener { shareDeepLink(newDeepLink.toString()) }
- // [END_EXCLUDE]
binding.buttonShareShortLink.setOnClickListener {
- val shortLinkTextView = findViewById(R.id.shortLinkViewSend);
- val shortDynamicLink = shortLinkTextView.text;
- shareDeepLink(shortDynamicLink.toString());
+ val shortDynamicLink = shortLinkTextView.text
+ shareDeepLink(shortDynamicLink.toString())
}
binding.buttonGenerateShortLink.setOnClickListener {
- val deepLink = Uri.parse(DEEP_LINK_URL);
- buildShortLinkFromParams(deepLink, 0);
+ val deepLink = Uri.parse(DEEP_LINK_URL)
+ viewModel.buildShortLinkFromParams(uriPrefix, deepLink, 0)
}
- // [START get_deep_link]
- Firebase.dynamicLinks
- .getDynamicLink(intent)
- .addOnSuccessListener(this) { pendingDynamicLinkData: PendingDynamicLinkData? ->
- // Get deep link from result (may be null if no link is found)
- var deepLink: Uri? = null
- if (pendingDynamicLinkData != null) {
- deepLink = pendingDynamicLinkData.link
- }
-
- // Handle the deep link. For example, open the linked
- // content, or apply promotional credit to the user's
- // account.
- // ...
-
- // [START_EXCLUDE]
- // Display deep link in the UI
- if (deepLink != null) {
- Snackbar.make(findViewById(android.R.id.content),
- "Found deep link!", Snackbar.LENGTH_LONG).show()
-
- linkReceiveTextView.text = deepLink.toString()
- } else {
- Log.d(TAG, "getDynamicLink: no link found")
- }
- // [END_EXCLUDE]
- }
- .addOnFailureListener(this) { e -> Log.w(TAG, "getDynamicLink:onFailure", e) }
- // [END get_deep_link]
- }
- // [END on_create]
-
- /**
- * Build a Firebase Dynamic Link.
- * https://firebase.google.com/docs/dynamic-links/android/create#create-a-dynamic-link-from-parameters
- *
- * @param deepLink the deep link your app will open. This link must be a valid URL and use the
- * HTTP or HTTPS scheme.
- * @param minVersion the `versionCode` of the minimum version of your app that can open
- * the deep link. If the installed app is an older version, the user is taken
- * to the Play store to upgrade the app. Pass 0 if you do not
- * require a minimum version.
- * @return a [Uri] representing a properly formed deep link.
- */
- @VisibleForTesting
- fun buildDeepLink(deepLink: Uri, minVersion: Int): Uri {
- val uriPrefix = getString(R.string.dynamic_links_uri_prefix)
+ viewModel.getDynamicLink(intent)
- // Set dynamic link parameters:
- // * URI prefix (required)
- // * Android Parameters (required)
- // * Deep link
- // [START build_dynamic_link]
- // Build the dynamic link
- val link = Firebase.dynamicLinks.dynamicLink {
- domainUriPrefix = uriPrefix
- androidParameters {
- minimumVersion = minVersion
+ lifecycleScope.launch {
+ viewModel.deepLink.collect { deepLink ->
+ if(deepLink.isNotEmpty()){
+ linkReceiveTextView.text = deepLink
+ Snackbar.make(findViewById(android.R.id.content),
+ "Found deep link!", Snackbar.LENGTH_LONG).show()
+ }
}
- link = deepLink
}
- // [END build_dynamic_link]
-
- // Return the dynamic link as a URI
- return link.uri
- }
- @VisibleForTesting
- fun buildShortLinkFromParams(deepLink: Uri, minVersion: Int) {
- val uriPrefix = getString(R.string.dynamic_links_uri_prefix)
+ lifecycleScope.launch {
+ viewModel.shortLink.collect { shortLink ->
+ if(shortLink.isNotEmpty()){
+ shortLinkTextView.text = shortLink
+ }
+ }
+ }
- // Set dynamic link parameters:
- // * URI prefix (required)
- // * Android Parameters (required)
- // * Deep link
- Firebase.dynamicLinks.shortLinkAsync {
- link = deepLink
- domainUriPrefix = uriPrefix
- androidParameters {
- minimumVersion = minVersion
+ lifecycleScope.launch {
+ viewModel.validUriPrefix.collect { flag ->
+ if(!flag){
+ AlertDialog.Builder(applicationContext)
+ .setTitle("Invalid Configuration")
+ .setMessage("Please set your Dynamic Links domain in app/build.gradle")
+ .setPositiveButton(android.R.string.ok, null)
+ .create().show()
+ }
}
- }.addOnSuccessListener { (shortLink, flowchartLink) ->
- val shortLinkTextView = findViewById(R.id.shortLinkViewSend);
- shortLinkTextView.text = shortLink.toString();
- }.addOnFailureListener(this) { e ->
- Log.e(TAG, e.toString());
}
+
+
}
private fun shareDeepLink(deepLink: String) {
@@ -151,17 +91,6 @@ class MainActivity : AppCompatActivity() {
startActivity(intent)
}
- private fun validateAppCode() {
- val uriPrefix = getString(R.string.dynamic_links_uri_prefix)
- if (uriPrefix.contains("YOUR_APP")) {
- AlertDialog.Builder(this)
- .setTitle("Invalid Configuration")
- .setMessage("Please set your Dynamic Links domain in app/build.gradle")
- .setPositiveButton(android.R.string.ok, null)
- .create().show()
- }
- }
-
companion object {
private const val TAG = "MainActivity"
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainComposeActivity.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainComposeActivity.kt
new file mode 100644
index 0000000000..8dcc7e54cf
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/MainComposeActivity.kt
@@ -0,0 +1,315 @@
+package com.google.firebase.quickstart.deeplinks.kotlin
+
+import android.app.Activity
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.net.Uri
+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.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.AlertDialog
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonDefaults
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.Scaffold
+import androidx.compose.material.SnackbarHostState
+import androidx.compose.material.Surface
+import androidx.compose.material.Text
+import androidx.compose.material.TopAppBar
+import androidx.compose.material.rememberScaffoldState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.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.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.viewmodel.compose.viewModel
+import com.google.firebase.quickstart.deeplinks.R
+import com.google.firebase.quickstart.deeplinks.kotlin.ui.theme.DynamicLinksTheme
+import kotlinx.coroutines.channels.Channel
+
+private const val DEEP_LINK_URL = "https://www.youtube.com/deeplinks"
+
+class MainComposeActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ setContent {
+ DynamicLinksTheme {
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = MaterialTheme.colors.background
+ ) {
+ MainAppView()
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun MainAppView(
+ lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
+ dynamicLinksViewModel: DynamicLinksViewModel = viewModel(factory = DynamicLinksViewModel.Factory)
+) {
+ val context = LocalContext.current
+ val activity = context.findActivity()
+ val intent = activity?.intent
+ val uriPrefix = stringResource(R.string.dynamic_links_uri_prefix)
+ var newDeepLink by remember { mutableStateOf("") }
+ var openDialog by remember { mutableStateOf(false) }
+
+ DisposableEffect(lifecycleOwner) {
+ val observer = LifecycleEventObserver { _, event ->
+ // Configure Firebase Dynamic Links when the screen is created
+ if (event == Lifecycle.Event.ON_CREATE) {
+ // Validate that the developer has set the app code.
+ dynamicLinksViewModel.validateAppCode(uriPrefix)
+
+ newDeepLink = dynamicLinksViewModel.buildDeepLink(uriPrefix, Uri.parse(DEEP_LINK_URL), 0).toString()
+
+ intent?.let {
+ dynamicLinksViewModel.getDynamicLink(it)
+ }
+ }
+ }
+
+ lifecycleOwner.lifecycle.addObserver(observer)
+
+ onDispose {
+ lifecycleOwner.lifecycle.removeObserver(observer)
+ }
+ }
+
+ val snackbarHostState = remember { SnackbarHostState() }
+ val channel = remember { Channel(Channel.Factory.CONFLATED) }
+ val scaffoldState = rememberScaffoldState(snackbarHostState = snackbarHostState)
+
+ // Checks if a valid uri has been updated, show only once
+ LaunchedEffect(key1 = true) {
+ dynamicLinksViewModel.validUriPrefix.collect { flag ->
+ if (!flag) {
+ openDialog = true
+ }
+ }
+ }
+
+ // Checks if a deep link is used to open app
+ LaunchedEffect(key1 = channel) {
+ dynamicLinksViewModel.deepLink.collect { deepLink ->
+ if (deepLink.isNotEmpty()) {
+ snackbarHostState.showSnackbar("Found deep link!")
+ }
+ }
+ }
+ Scaffold(
+ scaffoldState = scaffoldState,
+ topBar = {
+ TopAppBar(
+ backgroundColor = colorResource(R.color.colorPrimary)
+ ) {
+ Text(
+ text = stringResource(R.string.app_name),
+ style = MaterialTheme.typography.h6,
+ textAlign = TextAlign.Center,
+ modifier = Modifier.padding(8.dp),
+ color = Color.White
+ )
+ }
+ },
+ content = { it ->
+ Column(
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(it)
+ ) {
+ MainContent(
+ _openDialog = openDialog,
+ _linkReceiveTextView = dynamicLinksViewModel.deepLink.collectAsState(),
+ _shortLinkTextView = dynamicLinksViewModel.shortLink.collectAsState(),
+ newDeepLink = newDeepLink,
+ buildDeepLink = {
+ dynamicLinksViewModel.buildDeepLink(uriPrefix, Uri.parse(DEEP_LINK_URL), 0).toString()
+ },
+ buildShortLinkFromParams = {
+ dynamicLinksViewModel.buildShortLinkFromParams(uriPrefix, it, 0)
+ }
+ )
+ }
+ }
+ )
+}
+
+@Composable
+fun MainContent(
+ _openDialog: Boolean = false,
+ _linkReceiveTextView: State = mutableStateOf(""),
+ _shortLinkTextView: State = mutableStateOf(""),
+ newDeepLink: String = "",
+ buildDeepLink: () -> String = { "" },
+ buildShortLinkFromParams: (Uri) -> Unit = {},
+){
+ val context = LocalContext.current
+ var openDialog by remember { mutableStateOf(_openDialog) }
+ val linkReceiveTextView by _linkReceiveTextView
+ val shortLinkTextView by _shortLinkTextView
+
+ Column(
+ modifier = Modifier
+ .padding(16.dp)
+ .fillMaxWidth(),
+ ) {
+ if(openDialog) {
+ AlertDialog(
+ onDismissRequest = { openDialog = false },
+ title = { Text("Invalid Configuration") },
+ text = { Text("Please set your Dynamic Links domain in app/build.gradle") },
+ confirmButton = {
+ Button(onClick = {
+ openDialog = false
+ }) {
+ Text(stringResource(android.R.string.ok))
+ }
+ }
+ )
+ }
+
+ Image(
+ painter = painterResource(R.drawable.firebase_lockup_400),
+ contentDescription = "",
+ modifier = Modifier.fillMaxWidth(),
+ alignment = Alignment.Center
+ )
+
+ Text(
+ text = stringResource(R.string.title_receive),
+ fontSize = 20.sp,
+ style = MaterialTheme.typography.h6,
+ modifier = Modifier.padding(top = 8.dp)
+ )
+
+ Text(
+ text = linkReceiveTextView.ifEmpty {
+ stringResource(R.string.msg_no_deep_link)
+ },
+ fontSize = 16.sp,
+ modifier = Modifier.padding(top = 8.dp)
+ )
+
+ Text(
+ text = stringResource(R.string.dynamic_link),
+ fontSize = 20.sp,
+ style = MaterialTheme.typography.h6,
+ modifier = Modifier.padding(top = 32.dp)
+ )
+
+ Text(
+ text = buildDeepLink().ifEmpty { "https://abc.xyz/foo" },
+ fontSize = 16.sp,
+ modifier = Modifier.padding(top = 8.dp)
+ )
+
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorPrimary)),
+ onClick = {
+ shareDeepLink(context, newDeepLink)
+ }
+ ) {
+ Text(
+ text = stringResource(R.string.share_dynamic_link).uppercase(),
+ color = Color.White,
+ )
+ }
+
+ Text(
+ text = stringResource(R.string.short_dynamic_link),
+ fontSize = 20.sp,
+ style = MaterialTheme.typography.h6,
+ modifier = Modifier.padding(top = 32.dp)
+ )
+
+ Text(
+ text = shortLinkTextView.ifEmpty {
+ "https://abc.xyz/foo"
+ },
+ fontSize = 16.sp,
+ modifier = Modifier.padding(top = 8.dp)
+ )
+
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorPrimary)),
+ onClick = {
+ val deepLink = Uri.parse(DEEP_LINK_URL)
+ buildShortLinkFromParams(deepLink)
+ }
+ ) {
+ Text(
+ text = stringResource(R.string.generate_short_link).uppercase(),
+ color = Color.White
+ )
+ }
+
+ Button(
+ modifier = Modifier.fillMaxWidth(),
+ colors = ButtonDefaults.buttonColors(backgroundColor = colorResource(R.color.colorPrimary)),
+ onClick = {
+ shareDeepLink(context, shortLinkTextView)
+ }
+ ) {
+ Text(
+ text = stringResource(R.string.share_short_link).uppercase(),
+ color = Color.White
+ )
+ }
+ }
+}
+
+@Composable
+@Preview(showBackground = true)
+fun MainContentPreview(){
+ DynamicLinksTheme {
+ MainContent()
+ }
+}
+
+fun shareDeepLink(context: Context, deepLink: String) {
+ val intent = Intent(Intent.ACTION_SEND)
+ intent.type = "text/plain"
+ intent.putExtra(Intent.EXTRA_SUBJECT, "Firebase Deep Link")
+ intent.putExtra(Intent.EXTRA_TEXT, deepLink)
+
+ context.startActivity(intent)
+}
+
+fun Context.findActivity(): Activity? = when (this) {
+ is Activity -> this
+ is ContextWrapper -> baseContext.findActivity()
+ else -> null
+}
\ No newline at end of file
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Color.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Color.kt
new file mode 100644
index 0000000000..b500a555a1
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Color.kt
@@ -0,0 +1,11 @@
+package com.google.firebase.quickstart.deeplinks.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/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Shape.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Shape.kt
new file mode 100644
index 0000000000..b273cfb639
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Shape.kt
@@ -0,0 +1,11 @@
+package com.google.firebase.quickstart.deeplinks.kotlin.ui.theme
+
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Shapes
+import androidx.compose.ui.unit.dp
+
+val Shapes = Shapes(
+ small = RoundedCornerShape(16.dp),
+ medium = RoundedCornerShape(2.dp),
+ large = RoundedCornerShape(0.dp)
+)
\ No newline at end of file
diff --git a/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Theme.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Theme.kt
new file mode 100644
index 0000000000..f5aa458dd4
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Theme.kt
@@ -0,0 +1,48 @@
+package com.google.firebase.quickstart.deeplinks.kotlin.ui.theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material.MaterialTheme
+import androidx.compose.material.darkColors
+import androidx.compose.material.lightColors
+import androidx.compose.runtime.Composable
+
+private val DarkColorPalette = darkColors(
+ primary = Purple80,
+ primaryVariant = PurpleGrey80,
+ secondary = Pink80
+)
+
+private val LightColorPalette = lightColors(
+ primary = FirebaseBlue,
+ primaryVariant = FirebaseBannerBlue,
+ secondary = FirebaseOrange
+
+ /* Other default colors to override
+ background = Color(0xFFFFFBFE),
+ surface = Color(0xFFFFFBFE),
+ onPrimary = Color.White,
+ onSecondary = Color.White,
+ onTertiary = Color.White,
+ onBackground = Color(0xFF1C1B1F),
+ onSurface = Color(0xFF1C1B1F),
+ */
+)
+
+@Composable
+fun DynamicLinksTheme(
+ 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/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Type.kt b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Type.kt
new file mode 100644
index 0000000000..67f305a2fd
--- /dev/null
+++ b/dynamiclinks/app/src/main/java/com/google/firebase/quickstart/deeplinks/kotlin/ui/theme/Type.kt
@@ -0,0 +1,34 @@
+package com.google.firebase.quickstart.deeplinks.kotlin.ui.theme
+
+import androidx.compose.material.Typography
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontFamily
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+// Set of Material typography styles to start with
+val Typography = Typography(
+ body1 = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ lineHeight = 24.sp,
+ letterSpacing = 0.5.sp
+ )
+ /* Other default text styles to override
+ titleLarge = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Normal,
+ fontSize = 22.sp,
+ lineHeight = 28.sp,
+ letterSpacing = 0.sp
+ ),
+ labelSmall = TextStyle(
+ fontFamily = FontFamily.Default,
+ fontWeight = FontWeight.Medium,
+ fontSize = 11.sp,
+ lineHeight = 16.sp,
+ letterSpacing = 0.5.sp
+ )
+ */
+)
\ No newline at end of file
diff --git a/dynamiclinks/build.gradle b/dynamiclinks/build.gradle
index 07766d813c..1554d788ed 100644
--- a/dynamiclinks/build.gradle
+++ b/dynamiclinks/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/dynamiclinks/gradle.properties b/dynamiclinks/gradle.properties
index aac7c9b461..29b531a1d1 100644
--- a/dynamiclinks/gradle.properties
+++ b/dynamiclinks/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
diff --git a/firestore/app/build.gradle b/firestore/app/build.gradle
index 3595e1ea5a..3877cae5a1 100644
--- a/firestore/app/build.gradle
+++ b/firestore/app/build.gradle
@@ -8,16 +8,18 @@ plugins {
android {
namespace 'com.google.firebase.example.fireeats'
testBuildType "release"
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.example.fireeats"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
-
+ vectorDrawables {
+ useSupportLibrary true
+ }
vectorDrawables.useSupportLibrary true
lintOptions {
@@ -37,6 +39,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}'
+ }
}
}
@@ -84,6 +102,12 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
annotationProcessor 'androidx.lifecycle:lifecycle-compiler:2.5.1'
+ // 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'
+
// Third-party libraries
implementation 'me.zhanghai.android.materialratingbar:library:1.4.0'
implementation 'com.github.bumptech.glide:glide:4.12.0'
@@ -96,5 +120,8 @@ dependencies {
androidTestImplementation 'junit:junit:4.13.2'
androidTestImplementation 'org.hamcrest:hamcrest-library:2.2'
androidTestImplementation 'com.google.firebase:firebase-auth'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/firestore/build.gradle b/firestore/build.gradle
index 40c39f9f83..c50a5d8982 100644
--- a/firestore/build.gradle
+++ b/firestore/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3'
}
}
diff --git a/functions/app/build.gradle b/functions/app/build.gradle
index 8b6dd01bd4..ce9601ec52 100644
--- a/functions/app/build.gradle
+++ b/functions/app/build.gradle
@@ -8,15 +8,18 @@ android {
namespace 'com.google.samples.quickstart.functions'
// Changes the test build type for instrumented tests to "stage".
testBuildType "release"
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.samples.quickstart.functions"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -31,6 +34,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}'
+ }
}
}
@@ -42,6 +61,7 @@ dependencies {
implementation 'androidx.fragment:fragment-ktx:1.5.4'
implementation 'androidx.appcompat:appcompat:1.5.1'
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')
@@ -67,9 +87,18 @@ dependencies {
// Google Play services
implementation 'com.google.android.gms:play-services-auth:20.4.0'
+ // 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'
+
testImplementation 'junit:junit:4.13.2'
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.uiautomator:uiautomator:2.2.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/functions/build.gradle b/functions/build.gradle
index 07766d813c..1554d788ed 100644
--- a/functions/build.gradle
+++ b/functions/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/functions/firebase.json b/functions/firebase.json
index 0967ef424b..1bee05ed6d 100644
--- a/functions/firebase.json
+++ b/functions/firebase.json
@@ -1 +1,14 @@
-{}
+{
+ "functions": [
+ {
+ "source": "functions",
+ "codebase": "default",
+ "ignore": [
+ "node_modules",
+ ".git",
+ "firebase-debug.log",
+ "firebase-debug.*.log"
+ ]
+ }
+ ]
+}
diff --git a/inappmessaging/app/build.gradle b/inappmessaging/app/build.gradle
index 4dbfb82832..00b6c2746a 100644
--- a/inappmessaging/app/build.gradle
+++ b/inappmessaging/app/build.gradle
@@ -6,15 +6,18 @@ plugins {
android {
namespace 'com.google.firebase.fiamquickstart'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.fiamquickstart"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -28,6 +31,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}'
+ }
}
lint {
warning 'InvalidPackage'
@@ -41,9 +60,10 @@ dependencies {
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.multidex:multidex:2.0.1'
+ 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')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// FIAM (Java)
implementation 'com.google.firebase:firebase-inappmessaging-display'
@@ -60,8 +80,17 @@ dependencies {
implementation 'com.google.firebase:firebase-installations-ktx:17.1.0'
- androidTestImplementation 'androidx.test:runner:1.5.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
- androidTestImplementation 'androidx.test:rules:1.5.0'
+ // 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.test:runner:1.4.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/inappmessaging/build.gradle b/inappmessaging/build.gradle
index 9332ee6330..64c31555c4 100644
--- a/inappmessaging/build.gradle
+++ b/inappmessaging/build.gradle
@@ -10,7 +10,7 @@ buildscript {
dependencies {
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.android.tools.build:gradle:7.3.1'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/messaging/app/build.gradle b/messaging/app/build.gradle
index 1260588b71..9324342ec4 100644
--- a/messaging/app/build.gradle
+++ b/messaging/app/build.gradle
@@ -8,16 +8,18 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.firebase.quickstart.fcm'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.quickstart.fcm"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
-
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -36,6 +38,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}'
+ }
}
lint {
abortOnError false
@@ -52,6 +70,7 @@ dependencies {
// Required when asking for permission to post notifications (starting in Android 13)
implementation 'androidx.activity:activity-ktx:1.6.1'
implementation 'androidx.fragment:fragment-ktx:1.5.4'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation 'com.google.android.material:material:1.7.0'
@@ -72,9 +91,18 @@ dependencies {
implementation 'androidx.work:work-runtime:2.7.1'
+ // 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'
+
// Testing dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
androidTestImplementation 'androidx.test:runner:1.5.1'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.annotation:annotation:1.5.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/messaging/build.gradle b/messaging/build.gradle
index 98de3b7f07..f9bdde250d 100644
--- a/messaging/build.gradle
+++ b/messaging/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/perf/app/build.gradle b/perf/app/build.gradle
index f6da70a13c..f17e3c18b3 100644
--- a/perf/app/build.gradle
+++ b/perf/app/build.gradle
@@ -9,14 +9,17 @@ check.dependsOn 'assembleDebugAndroidTest'
android {
namespace 'com.google.firebase.quickstart.perfmon'
- compileSdkVersion 33
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.quickstart.perfmon"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -35,6 +38,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}'
+ }
}
}
@@ -43,7 +62,7 @@ dependencies {
implementation project(":internal:chooserx")
// Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom)
- implementation platform('com.google.firebase:firebase-bom:31.1.0')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Firebase Performance Monitoring (Java)
implementation 'com.google.firebase:firebase-perf'
@@ -57,6 +76,15 @@ dependencies {
implementation 'com.github.bumptech.glide:glide:4.12.0'
+ // 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'
+
testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/perf/build.gradle b/perf/build.gradle
index 5b63840354..9b357abce3 100644
--- a/perf/build.gradle
+++ b/perf/build.gradle
@@ -10,7 +10,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.firebase:perf-plugin:1.4.2'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}
diff --git a/storage/app/build.gradle b/storage/app/build.gradle
index 3e5a81a2d9..db63bbbc27 100644
--- a/storage/app/build.gradle
+++ b/storage/app/build.gradle
@@ -7,15 +7,19 @@ plugins {
check.dependsOn 'assembleDebugAndroidTest'
android {
- compileSdkVersion 33
+ namespace 'com.google.firebase.quickstart.firebasestorage'
+ compileSdk 33
defaultConfig {
applicationId "com.google.firebase.quickstart.firebasestorage"
- minSdkVersion 19
- targetSdkVersion 33
+ minSdk 21 // minSdk would be 19 without compose
+ targetSdk 33
versionCode 1
versionName "1.0"
multiDexEnabled true
+ vectorDrawables {
+ useSupportLibrary true
+ }
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
@@ -28,8 +32,23 @@ 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}'
+ }
}
- namespace 'com.google.firebase.quickstart.firebasestorage'
}
dependencies {
@@ -37,7 +56,7 @@ dependencies {
implementation project(":internal:chooserx")
// Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom)
- implementation platform('com.google.firebase:firebase-bom:31.1.0')
+ implementation platform('com.google.firebase:firebase-bom:31.0.2')
// Cloud Storage for Firebase (Java)
implementation 'com.google.firebase:firebase-storage'
@@ -52,10 +71,20 @@ dependencies {
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'androidx.activity:activity-ktx:1.6.1'
+ // 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.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
- androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.0'
- androidTestImplementation 'androidx.test:rules:1.5.0'
- androidTestImplementation 'androidx.test:runner:1.5.1'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
+ androidTestImplementation 'androidx.test:rules:1.4.0'
+ androidTestImplementation 'androidx.test:runner:1.4.0'
+ androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
+ debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
}
diff --git a/storage/build.gradle b/storage/build.gradle
index 8c2f8a5842..cdf5c6bb90 100644
--- a/storage/build.gradle
+++ b/storage/build.gradle
@@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.google.gms:google-services:4.3.14'
- classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.21'
+ classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20'
}
}