diff --git a/.opensource/project.json b/.opensource/project.json index b756e295a..ab51045f5 100644 --- a/.opensource/project.json +++ b/.opensource/project.json @@ -20,7 +20,8 @@ "storage/README.md", "firestore/README.md", "docs/upgrade-to-2.0.md", - "docs/upgrade-to-3.0.md" + "docs/upgrade-to-3.0.md", + "docs/upgrade-to-4.0.md" ], // Related projects on Github, in the format $owner/$repo[/$subproject] diff --git a/README.md b/README.md index ae5145744..00ca87bdd 100644 --- a/README.md +++ b/README.md @@ -47,16 +47,16 @@ libraries. ```groovy dependencies { // FirebaseUI for Firebase Realtime Database - implementation 'com.firebaseui:firebase-ui-database:3.3.1' + implementation 'com.firebaseui:firebase-ui-database:4.0.0' // FirebaseUI for Cloud Firestore - implementation 'com.firebaseui:firebase-ui-firestore:3.3.1' + implementation 'com.firebaseui:firebase-ui-firestore:4.0.0' // FirebaseUI for Firebase Auth - implementation 'com.firebaseui:firebase-ui-auth:3.3.1' + implementation 'com.firebaseui:firebase-ui-auth:4.0.0' // FirebaseUI for Cloud Storage - implementation 'com.firebaseui:firebase-ui-storage:3.3.1' + implementation 'com.firebaseui:firebase-ui-storage:4.0.0' } ``` @@ -70,6 +70,7 @@ After the project is synchronized, we're ready to start using Firebase functiona If you are using an old version of FirebaseUI and upgrading, please see the appropriate migration guide: +* [Upgrade from 3.3.1 to 4.x.x](./docs/upgrade-to-4.0.md) * [Upgrade from 2.3.0 to 3.x.x](./docs/upgrade-to-3.0.md) * [Upgrade from 1.2.0 to 2.x.x](./docs/upgrade-to-2.0.md) @@ -93,24 +94,20 @@ firebase-ui-storage |--- com.google.firebase:firebase-storage ``` -Each version of FirebaseUI has dependency on a fixed version of these libraries, defined as the variable `firebase_version` -in `common/constants.gradle`. If you are using any dependencies in your app of the form -`implementation 'com.google.firebase:firebase-*:x.y.z'` or -`implementation 'com.google.android.gms:play-services-*:x.y.z'` -you need to make sure that you use the same version that your chosen version of FirebaseUI requires. +As of version `15.0.0`, Firebase and Google Play services libraries have independent, semantic +versions. This means that FirebaseUI has independent dependencies on each of the libraries above. +For best results, your app should depend on a version of each dependency with the same major +version number as the version used by FirebaseUI. -For convenience, here are some recent examples: - -| FirebaseUI Version | Firebase/Play Services Version | -|--------------------|--------------------------------| -| 3.3.1 | 15.0.0 | -| 3.3.0 | 12.0.1 | -| 3.2.2 | 11.8.0 | -| 3.1.3 | 11.8.0 | -| 3.0.0 | 11.4.2 | -| 2.4.0 | 11.4.0 | -| 1.1.1 | 10.0.0 or 10.0.1 | +As of version `4.0.0`, FirebaseUI has the following dependency versions: +| Library | Version | +|----------------------|--------------------------------| +| `firebase-auth` | 15.1.0 | +| `play-services-auth` | 15.0.1 | +| `firebase-database` | 15.0.1 | +| `firebase-firestore` | 16.0.0 | +| `firebase-storage` | 15.0.2 | ### Upgrading dependencies diff --git a/app/build.gradle b/app/build.gradle index 8ec70a284..1dfc16e00 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -36,7 +36,7 @@ android { } dependencies { - implementation "com.google.firebase:firebase-core:$firebaseVersion" + implementation "com.google.firebase:firebase-core:$coreVersion" implementation "com.android.support:design:$supportLibraryVersion" implementation 'com.android.support:multidex:1.0.3' @@ -45,14 +45,17 @@ dependencies { implementation project(path: ':database') implementation project(path: ':storage') - implementation 'com.facebook.android:facebook-login:4.31.0' + implementation 'com.facebook.android:facebook-login:4.32.0' // Needed to override Facebook implementation "com.android.support:cardview-v7:$supportLibraryVersion" implementation "com.android.support:customtabs:$supportLibraryVersion" implementation("com.twitter.sdk.android:twitter-core:3.1.1@aar") { transitive = true } - implementation 'com.github.bumptech.glide:glide:4.6.1' - annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1' + implementation 'com.github.bumptech.glide:glide:4.7.1' + annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1' + + // Used for FirestorePagingActivity + implementation "android.arch.paging:runtime:$pagingVersion" // The following dependencies are not required to use the Firebase UI library. // They are used to make some aspects of the demo app implementation simpler for diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 78baf88a5..0a381a18c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -43,6 +43,11 @@ android:name=".database.firestore.FirestoreChatActivity" android:label="@string/title_firestore_activity" /> + + + () { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + startSignedInActivity(null); + } else { + showSnackbar(R.string.sign_in_failed); + } + } + }); + } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); diff --git a/app/src/main/java/com/firebase/uidemo/database/firestore/FirestorePagingActivity.java b/app/src/main/java/com/firebase/uidemo/database/firestore/FirestorePagingActivity.java new file mode 100644 index 000000000..f3f92fe34 --- /dev/null +++ b/app/src/main/java/com/firebase/uidemo/database/firestore/FirestorePagingActivity.java @@ -0,0 +1,197 @@ +package com.firebase.uidemo.database.firestore; + +import android.arch.paging.PagedList; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.firebase.ui.firestore.paging.FirestorePagingAdapter; +import com.firebase.ui.firestore.paging.FirestorePagingOptions; +import com.firebase.ui.firestore.paging.LoadingState; +import com.firebase.uidemo.R; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.firestore.CollectionReference; +import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.firestore.Query; +import com.google.firebase.firestore.WriteBatch; + +import java.util.Locale; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class FirestorePagingActivity extends AppCompatActivity { + + private static final String TAG = "FirestorePagingActivity"; + + @BindView(R.id.paging_recycler) + RecyclerView mRecycler; + + @BindView(R.id.paging_loading) + ProgressBar mProgressBar; + + private FirebaseFirestore mFirestore; + private CollectionReference mItemsCollection; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_firestore_paging); + ButterKnife.bind(this); + + mFirestore = FirebaseFirestore.getInstance(); + mItemsCollection = mFirestore.collection("items"); + + setUpAdapter(); + } + + private void setUpAdapter() { + Query baseQuery = mItemsCollection.orderBy("value", Query.Direction.ASCENDING); + + PagedList.Config config = new PagedList.Config.Builder() + .setEnablePlaceholders(false) + .setPrefetchDistance(10) + .setPageSize(20) + .build(); + + FirestorePagingOptions options = new FirestorePagingOptions.Builder() + .setLifecycleOwner(this) + .setQuery(baseQuery, config, Item.class) + .build(); + + FirestorePagingAdapter adapter = + new FirestorePagingAdapter(options) { + @NonNull + @Override + public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, + int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_item, parent, false); + return new ItemViewHolder(view); + } + + @Override + protected void onBindViewHolder(@NonNull ItemViewHolder holder, + int position, + Item model) { + holder.bind(model); + } + + @Override + protected void onLoadingStateChanged(@NonNull LoadingState state) { + switch (state) { + case LOADING_INITIAL: + case LOADING_MORE: + mProgressBar.setVisibility(View.VISIBLE); + break; + case LOADED: + mProgressBar.setVisibility(View.GONE); + break; + case FINISHED: + mProgressBar.setVisibility(View.GONE); + showToast("Reached end of data set."); + break; + case ERROR: + showToast("An error occurred."); + retry(); + break; + } + } + }; + + mRecycler.setLayoutManager(new LinearLayoutManager(this)); + mRecycler.setAdapter(adapter); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_firestore_paging, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.item_add_data) { + showToast("Adding data..."); + createItems().addOnCompleteListener(this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + showToast("Data added."); + } else { + Log.w(TAG, "addData", task.getException()); + showToast("Error adding data."); + } + } + }); + + return true; + } + return super.onOptionsItemSelected(item); + } + + private Task createItems() { + WriteBatch writeBatch = mFirestore.batch(); + + for (int i = 0; i < 250; i++) { + String title = "Item " + i; + + String id = String.format(Locale.getDefault(), "item_%03d", i); + Item item = new Item(title, i); + + writeBatch.set(mItemsCollection.document(id), item); + } + + return writeBatch.commit(); + } + + private void showToast(String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + + public static class Item { + + public String text; + public int value; + + public Item() {} + + public Item(String text, int value) { + this.text = text; + this.value = value; + } + + } + + public static class ItemViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.item_text) + TextView mTextView; + + @BindView(R.id.item_value) + TextView mValueView; + + ItemViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + void bind(Item item) { + mTextView.setText(item.text); + mValueView.setText(String.valueOf(item.value)); + } + } + +} diff --git a/app/src/main/res/layout/activity_firestore_paging.xml b/app/src/main/res/layout/activity_firestore_paging.xml new file mode 100644 index 000000000..0febad887 --- /dev/null +++ b/app/src/main/res/layout/activity_firestore_paging.xml @@ -0,0 +1,30 @@ + + + + + + + + diff --git a/app/src/main/res/layout/auth_ui_layout.xml b/app/src/main/res/layout/auth_ui_layout.xml index f04e55725..18e092837 100644 --- a/app/src/main/res/layout/auth_ui_layout.xml +++ b/app/src/main/res/layout/auth_ui_layout.xml @@ -35,9 +35,18 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_margin="16dp" + android:layout_marginTop="16dp" android:text="@string/sign_in_start" /> +