-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Firebase Data Connect quickstart (#1671)
* Initial commit for dataconnect sample app * chore: add Firebase dependencies * add first schema * update with new schema * add kotlin serialization and androidx.lifecycle * firebase init * setup bottom navigation * feat: create movies screen * add firebase data connect logo * add top 10 movies and latest to the MoviesScreen * create GenresScreen * create GenreDetailScreen * create MovieDetailScreen * chore: bump gradle plugins * test: delete test modules * chore: add compose compiler * chore: move location from firebase.json to dataconnect.yaml * feat: create an auth screen * create user profile favorites list and sign out button * ellipsize text in Movie Tile * refactor: reuse MovieTile UI component * delete UserRepository * refactor: delete MovieRepository * refactor: delete the data package * feat: list actors in the movie details screen * refactor: movie review list to bottom of profile screen * feat: add reviews to movie detail screen * refactor: dateformat for reviews * feat: mark movies as watched and/or favorite * refactor: move AuthScreen into its own file * docs: add a README file * feat: support reviewing movies :) * feat: create actor details screen * refactor: make actor list reusable * refactor: make movies list reusable * refactor: make error and loading reusable components * refactor: make toggle button reusable * refactor: make actor details screen stateless * refactor: move UserReviews into its own dedicated file * refactor: turn actor tile into a card * docs: update the getting started * docs: update README.md * docs: update README.md * add data_seed.gql and useEmulator() * Update README.md Co-authored-by: Marina Coelho <[email protected]> * refactor: use Navigation type safety * refactor: delete extra uiState * refactor favoriteActor for readability * refactor: make error messages nullable and add default error message * refactor: ensure a user is logged in before marking as favorite * update GenreDetailScreen * chore: use v1beta * ci: remove Data Connect from build * chore: upgrade to 16.0.0-beta01 * ci: remove -i parameter * ci: output file * ci: overwrite instead of append * chore: agp 8.7.0 * testing * revert ci changes * ci: add python script to remove fdc * docs: update README.md * docs: remove deploy step --------- Co-authored-by: Marina Coelho <[email protected]>
- Loading branch information
1 parent
0892912
commit 984eefa
Showing
70 changed files
with
4,307 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
*.iml | ||
.gradle | ||
/local.properties | ||
/.idea/caches | ||
/.idea/libraries | ||
/.idea/modules.xml | ||
/.idea/workspace.xml | ||
/.idea/navEditor.xml | ||
/.idea/assetWizardSettings.xml | ||
.DS_Store | ||
/build | ||
/captures | ||
.externalNativeBuild | ||
.cxx | ||
local.properties | ||
.dataconnect/ | ||
.firebaserc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Firebase Data Connect Quickstart | ||
|
||
## Introduction | ||
|
||
This quickstart is a movie review app to demonstrate the use of Firebase Data Connect | ||
with a Cloud SQL database. | ||
For more information about Firebase Data Connect visit [the docs](https://firebase.google.com/docs/data-connect/). | ||
|
||
## Getting Started | ||
|
||
Follow these steps to get up and running with Firebase Data Connect. For more detailed instructions, | ||
check out the [official documentation](https://firebase.google.com/docs/data-connect/quickstart). | ||
|
||
### 0. Prerequisites | ||
- Latest version of [Android Studio](https://developer.android.com/studio) | ||
- Latest version of [Visual Studio Code](https://code.visualstudio.com/) | ||
- The [Firebase Data Connect VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GoogleCloudTools.firebase-dataconnect-vscode) | ||
|
||
### 1. Connect to your Firebase project | ||
|
||
1. If you haven't already, create a Firebase project. | ||
1. In the [Firebase console](https://console.firebase.google.com), click | ||
**Add project**, then follow the on-screen instructions. | ||
|
||
2. Upgrade your project to the Blaze plan. This lets you create a Cloud SQL | ||
for PostgreSQL instance. | ||
|
||
> Note: Though you set up billing in your Blaze upgrade, you won't be | ||
charged for usage of Firebase Data Connect or the | ||
[default Cloud SQL for PostgreSQL configuration](https://firebase.google.com/docs/data-connect/#pricing) | ||
during the preview. | ||
|
||
3. Navigate to the [Data Connect section](https://console.firebase.google.com/u/0/project/_/dataconnect) | ||
of the Firebase console, click on the "Get Started" button and follow the setup workflow: | ||
- Select a location for your Cloud SQL for PostgreSQL database (this sample uses `us-central1`). If you choose a different location, you'll also need to change the `quickstart-android/dataconnect/dataconnect/dataconnect.yaml` file. | ||
- Select the option to create a new Cloud SQL instance and fill in the following fields: | ||
- Service ID: `dataconnect` | ||
- Cloud SQL Instance ID: `fdc-sql` | ||
- Database name: `fdcdb` | ||
4. Allow some time for the Cloud SQL instance to be provisioned. After it's provisioned, the instance | ||
can be managed in the [Cloud Console](https://console.cloud.google.com/sql). | ||
|
||
5. If you haven’t already, add an Android app to your Firebase project, with the android package name `com.google.firebase.example.dataconnect`. | ||
Click **Download google-services.json** to obtain your Firebase Android config file. | ||
|
||
### 2. Cloning the repository | ||
|
||
1. Clone this repository to your local machine: | ||
```sh | ||
git clone https://github.com/firebase/quickstart-android.git | ||
``` | ||
|
||
2. Move the `google-services.json` config file (downloaded in the previous step) into the | ||
`quickstart-android/dataconnect/app/` directory. | ||
|
||
### 3. Open in Visual Studio Code (VS Code) | ||
|
||
1. Open the `quickstart-android/dataconnect` directory in VS Code. | ||
2. Click on the Firebase Data Connect icon on the VS Code sidebar to load the Extension. | ||
a. Sign in with your Google Account if you haven't already. | ||
3. Click on "Connect a Firebase project" and choose the project where you have set up Data Connect. | ||
4. Click on "Start Emulators" - this should generate the Kotlin SDK for you and start the emulators. | ||
|
||
### 4. Populate the database | ||
In VS Code, open the `quickstart-android/dataconnect/dataconnect/data_seed.gql` file and click the | ||
`Run (local)` button at the top of the file. | ||
|
||
If you’d like to confirm that the data was correctly inserted, | ||
open `quickstart-android/dataconnect/connectors/queries.gql` and run the `ListMovies` query. | ||
|
||
### 5. Running the app | ||
|
||
Press the Run button in Android Studio to run the sample app on your device. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
plugins { | ||
alias(libs.plugins.android.application) | ||
alias(libs.plugins.jetbrains.kotlin.android) | ||
alias(libs.plugins.kotlin.serialization) | ||
alias(libs.plugins.google.services) | ||
alias(libs.plugins.compose.compiler) | ||
} | ||
|
||
android { | ||
namespace = "com.google.firebase.example.dataconnect" | ||
compileSdk = 34 | ||
|
||
defaultConfig { | ||
applicationId = "com.google.firebase.example.dataconnect" | ||
minSdk = 23 | ||
targetSdk = 34 | ||
versionCode = 1 | ||
versionName = "1.0" | ||
|
||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||
vectorDrawables { | ||
useSupportLibrary = true | ||
} | ||
} | ||
|
||
buildTypes { | ||
release { | ||
isMinifyEnabled = false | ||
proguardFiles( | ||
getDefaultProguardFile("proguard-android-optimize.txt"), | ||
"proguard-rules.pro" | ||
) | ||
} | ||
} | ||
compileOptions { | ||
sourceCompatibility = JavaVersion.VERSION_1_8 | ||
targetCompatibility = JavaVersion.VERSION_1_8 | ||
} | ||
kotlinOptions { | ||
jvmTarget = "1.8" | ||
} | ||
buildFeatures { | ||
compose = true | ||
} | ||
composeOptions { | ||
kotlinCompilerExtensionVersion = "1.5.13" | ||
} | ||
packaging { | ||
resources { | ||
excludes += "/META-INF/{AL2.0,LGPL2.1}" | ||
} | ||
} | ||
sourceSets.getByName("main") { | ||
java.srcDirs("build/generated/sources") | ||
} | ||
} | ||
|
||
dependencies { | ||
|
||
implementation(libs.androidx.core.ktx) | ||
implementation(libs.androidx.lifecycle.runtime.ktx) | ||
implementation(libs.androidx.lifecycle.viewmodel.compose) | ||
implementation(libs.androidx.activity.compose) | ||
implementation(platform(libs.androidx.compose.bom)) | ||
implementation(libs.androidx.ui) | ||
implementation(libs.androidx.ui.graphics) | ||
implementation(libs.androidx.ui.tooling.preview) | ||
implementation(libs.androidx.material3) | ||
implementation(libs.compose.navigation) | ||
implementation(libs.androidx.lifecycle.runtime.compose.android) | ||
implementation(libs.coil.compose) | ||
|
||
// Firebase dependencies | ||
implementation(libs.firebase.auth) | ||
implementation(libs.firebase.dataconnect) | ||
implementation(libs.kotlinx.serialization.core) | ||
|
||
testImplementation(libs.junit) | ||
androidTestImplementation(libs.androidx.junit) | ||
androidTestImplementation(libs.androidx.espresso.core) | ||
androidTestImplementation(platform(libs.androidx.compose.bom)) | ||
androidTestImplementation(libs.androidx.ui.test.junit4) | ||
debugImplementation(libs.androidx.ui.tooling) | ||
debugImplementation(libs.androidx.ui.test.manifest) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:tools="http://schemas.android.com/tools"> | ||
|
||
<uses-permission android:name="android.permission.INTERNET" /> | ||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | ||
|
||
<application | ||
android:allowBackup="true" | ||
android:dataExtractionRules="@xml/data_extraction_rules" | ||
android:fullBackupContent="@xml/backup_rules" | ||
android:icon="@mipmap/ic_launcher" | ||
android:label="@string/app_name" | ||
android:roundIcon="@mipmap/ic_launcher_round" | ||
android:supportsRtl="true" | ||
android:theme="@style/Theme.FirebaseDataConnect" | ||
tools:targetApi="31"> | ||
<activity | ||
android:name=".MainActivity" | ||
android:exported="true" | ||
android:label="@string/app_name" | ||
android:theme="@style/Theme.FirebaseDataConnect"> | ||
<intent-filter> | ||
<action android:name="android.intent.action.MAIN" /> | ||
|
||
<category android:name="android.intent.category.LAUNCHER" /> | ||
</intent-filter> | ||
</activity> | ||
</application> | ||
|
||
</manifest> |
135 changes: 135 additions & 0 deletions
135
dataconnect/app/src/main/java/com/google/firebase/example/dataconnect/MainActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
package com.google.firebase.example.dataconnect | ||
|
||
import android.os.Bundle | ||
import androidx.activity.ComponentActivity | ||
import androidx.activity.compose.setContent | ||
import androidx.activity.enableEdgeToEdge | ||
import androidx.compose.foundation.layout.consumeWindowInsets | ||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.Home | ||
import androidx.compose.material.icons.filled.Menu | ||
import androidx.compose.material.icons.filled.Person | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.NavigationBar | ||
import androidx.compose.material3.NavigationBarItem | ||
import androidx.compose.material3.Scaffold | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.getValue | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.vector.ImageVector | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.navigation.NavDestination.Companion.hasRoute | ||
import androidx.navigation.NavDestination.Companion.hierarchy | ||
import androidx.navigation.compose.NavHost | ||
import androidx.navigation.compose.composable | ||
import androidx.navigation.compose.currentBackStackEntryAsState | ||
import androidx.navigation.compose.rememberNavController | ||
import com.google.firebase.dataconnect.movies.MoviesConnector | ||
import com.google.firebase.dataconnect.movies.instance | ||
import com.google.firebase.example.dataconnect.feature.actordetail.ActorDetailRoute | ||
import com.google.firebase.example.dataconnect.feature.actordetail.ActorDetailScreen | ||
import com.google.firebase.example.dataconnect.feature.genredetail.GenreDetailRoute | ||
import com.google.firebase.example.dataconnect.feature.genredetail.GenreDetailScreen | ||
import com.google.firebase.example.dataconnect.feature.genres.GenresRoute | ||
import com.google.firebase.example.dataconnect.feature.genres.GenresScreen | ||
import com.google.firebase.example.dataconnect.feature.moviedetail.MovieDetailRoute | ||
import com.google.firebase.example.dataconnect.feature.moviedetail.MovieDetailScreen | ||
import com.google.firebase.example.dataconnect.feature.movies.MoviesRoute | ||
import com.google.firebase.example.dataconnect.feature.movies.MoviesScreen | ||
import com.google.firebase.example.dataconnect.feature.profile.ProfileRoute | ||
import com.google.firebase.example.dataconnect.feature.profile.ProfileScreen | ||
import com.google.firebase.example.dataconnect.feature.search.searchScreen | ||
import com.google.firebase.example.dataconnect.ui.theme.FirebaseDataConnectTheme | ||
|
||
data class TopLevelRoute<T : Any>(val labelResId: Int, val route: T, val icon: ImageVector) | ||
|
||
val TOP_LEVEL_ROUTES = listOf( | ||
TopLevelRoute(R.string.label_movies, MoviesRoute, Icons.Filled.Home), | ||
TopLevelRoute(R.string.label_genres, GenresRoute, Icons.Filled.Menu), | ||
TopLevelRoute(R.string.label_profile, ProfileRoute, Icons.Filled.Person) | ||
) | ||
|
||
class MainActivity : ComponentActivity() { | ||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
enableEdgeToEdge() | ||
// Comment the line below to use a production environment instead | ||
MoviesConnector.instance.dataConnect.useEmulator("10.0.2.2", 9399) | ||
setContent { | ||
FirebaseDataConnectTheme { | ||
val navController = rememberNavController() | ||
Scaffold( | ||
modifier = Modifier.fillMaxSize(), | ||
bottomBar = { | ||
NavigationBar { | ||
val navBackStackEntry by navController.currentBackStackEntryAsState() | ||
val currentDestination = navBackStackEntry?.destination | ||
|
||
TOP_LEVEL_ROUTES.forEach { topLevelRoute -> | ||
val label = stringResource(topLevelRoute.labelResId) | ||
NavigationBarItem( | ||
icon = { Icon(topLevelRoute.icon, contentDescription = label) }, | ||
label = { Text(label) }, | ||
selected = currentDestination?.hierarchy?.any { | ||
it.hasRoute(topLevelRoute.route::class) | ||
} == true, | ||
onClick = { | ||
navController.navigate( | ||
topLevelRoute.route, | ||
{ launchSingleTop = true } | ||
) | ||
} | ||
) | ||
} | ||
} | ||
} | ||
) { innerPadding -> | ||
NavHost( | ||
navController, | ||
startDestination = MoviesRoute, | ||
Modifier | ||
.padding(innerPadding) | ||
.consumeWindowInsets(innerPadding), | ||
) { | ||
composable<MoviesRoute>() { | ||
MoviesScreen( | ||
onMovieClicked = { movieId -> | ||
navController.navigate( | ||
route = MovieDetailRoute(movieId), | ||
builder = { | ||
launchSingleTop = true | ||
} | ||
) | ||
} | ||
) | ||
} | ||
composable<MovieDetailRoute> { | ||
MovieDetailScreen( | ||
onActorClicked = { actorId -> | ||
navController.navigate( | ||
ActorDetailRoute(actorId), | ||
{ launchSingleTop = true } | ||
) | ||
} | ||
) | ||
} | ||
composable<ActorDetailRoute>() { ActorDetailScreen() } | ||
composable<GenresRoute> { | ||
GenresScreen(onGenreClicked = { genre -> | ||
navController.navigate( | ||
GenreDetailRoute(genre), | ||
{ launchSingleTop = true } | ||
) | ||
}) | ||
} | ||
composable<GenreDetailRoute> { GenreDetailScreen() } | ||
searchScreen() | ||
composable<ProfileRoute> { ProfileScreen() } | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.