Skip to content

Commit e30ca58

Browse files
authored
Merge pull request #1 from FirebasePrivate/firestore
Firestore + FirebaseUI
2 parents d871c7a + 9f00117 commit e30ca58

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1463
-270
lines changed

app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dependencies {
3737

3838
compile project(path: ':auth')
3939
compile project(path: ':database')
40+
compile project(path: ':firestore')
4041
compile project(path: ':storage')
4142

4243
compile "com.google.android.gms:play-services-auth:$firebaseVersion"
@@ -47,6 +48,9 @@ dependencies {
4748
compile('com.facebook.android:facebook-android-sdk:4.25.0')
4849
compile("com.twitter.sdk.android:twitter-core:3.0.0@aar") { transitive = true }
4950

51+
compile "android.arch.lifecycle:runtime:$architectureVersion"
52+
compile "android.arch.lifecycle:extensions:$architectureVersion"
53+
5054
// The following dependencies are not required to use the Firebase UI library.
5155
// They are used to make some aspects of the demo app implementation simpler for
5256
// demonstrative purposes, and you may find them useful in your own apps; YMMV.

app/src/main/AndroidManifest.xml

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<manifest
3-
xmlns:android="http://schemas.android.com/apk/res/android"
4-
xmlns:tools="http://schemas.android.com/tools"
5-
package="com.firebase.uidemo">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.firebase.uidemo">
65

76
<uses-permission android:name="android.permission.INTERNET" />
87
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -21,8 +20,10 @@
2120
<activity android:name=".ChooserActivity">
2221
<intent-filter>
2322
<action android:name="android.intent.action.MAIN" />
23+
2424
<category android:name="android.intent.category.LAUNCHER" />
2525
</intent-filter>
26+
2627
<meta-data
2728
android:name="android.app.shortcuts"
2829
android:resource="@xml/shortcuts" />
@@ -36,6 +37,11 @@
3637
android:name=".database.ChatIndexActivity"
3738
android:label="@string/name_chat" />
3839

40+
<!-- Firestore demo -->
41+
<activity
42+
android:name=".firestore.FirestoreChatActivity"
43+
android:label="@string/name_chat"/>
44+
3945
<!-- Auth UI demo -->
4046
<activity
4147
android:name=".auth.AuthUiActivity"
@@ -44,7 +50,7 @@
4450
android:name=".auth.SignedInActivity"
4551
android:label="@string/name_auth_ui" />
4652

47-
<!-- Storage UI demo-->
53+
<!-- Storage UI demo -->
4854
<activity
4955
android:name=".storage.ImageActivity"
5056
android:label="@string/name_image" />

app/src/main/java/com/firebase/uidemo/ChooserActivity.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727

2828
import com.firebase.uidemo.auth.AuthUiActivity;
2929
import com.firebase.uidemo.database.ChatActivity;
30+
import com.firebase.uidemo.firestore.FirestoreChatActivity;
3031
import com.firebase.uidemo.storage.ImageActivity;
3132

3233
import butterknife.BindView;
@@ -50,18 +51,21 @@ protected void onCreate(Bundle savedInstanceState) {
5051
private static class ActivityChooserAdapter extends RecyclerView.Adapter<ActivityStarterHolder> {
5152
private static final Class[] CLASSES = new Class[]{
5253
ChatActivity.class,
54+
FirestoreChatActivity.class,
5355
AuthUiActivity.class,
5456
ImageActivity.class,
5557
};
5658

5759
private static final int[] DESCRIPTION_NAMES = new int[]{
5860
R.string.name_chat,
61+
R.string.name_firestore_chat,
5962
R.string.name_auth_ui,
6063
R.string.name_image
6164
};
6265

6366
private static final int[] DESCRIPTION_IDS = new int[]{
6467
R.string.desc_chat,
68+
R.string.desc_firestore_chat,
6569
R.string.desc_auth_ui,
6670
R.string.desc_image
6771
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.firebase.uidemo.database;
2+
3+
/**
4+
* Common interface for chat messages, helps share code between RTDB and Firestore examples.
5+
*/
6+
public abstract class AbstractChat {
7+
8+
public abstract String getName();
9+
10+
public abstract String getMessage();
11+
12+
public abstract String getUid();
13+
14+
15+
}

app/src/main/java/com/firebase/uidemo/database/Chat.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.firebase.uidemo.database;
22

3-
public class Chat {
3+
import com.google.firebase.database.IgnoreExtraProperties;
4+
5+
@IgnoreExtraProperties
6+
public class Chat extends AbstractChat {
7+
48
private String mName;
59
private String mMessage;
610
private String mUid;

app/src/main/java/com/firebase/uidemo/database/ChatHolder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public ChatHolder(View itemView) {
3838
mGray300 = ContextCompat.getColor(itemView.getContext(), R.color.material_gray_300);
3939
}
4040

41-
public void bind(Chat chat) {
41+
public void bind(AbstractChat chat) {
4242
setName(chat.getName());
4343
setText(chat.getMessage());
4444

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.firebase.uidemo.firestore;
2+
3+
import com.firebase.uidemo.database.AbstractChat;
4+
import com.google.firebase.firestore.IgnoreExtraProperties;
5+
import com.google.firebase.firestore.ServerTimestamp;
6+
7+
import java.util.Date;
8+
9+
@IgnoreExtraProperties
10+
public class Chat extends AbstractChat {
11+
12+
private String mName;
13+
private String mMessage;
14+
private String mUid;
15+
private @ServerTimestamp Date mTimestamp;
16+
17+
public Chat() {
18+
// Needed for Firebase
19+
}
20+
21+
public Chat(String name, String message, String uid) {
22+
mName = name;
23+
mMessage = message;
24+
mUid = uid;
25+
}
26+
27+
public String getName() {
28+
return mName;
29+
}
30+
31+
public void setName(String name) {
32+
mName = name;
33+
}
34+
35+
public String getMessage() {
36+
return mMessage;
37+
}
38+
39+
public void setMessage(String message) {
40+
mMessage = message;
41+
}
42+
43+
public String getUid() {
44+
return mUid;
45+
}
46+
47+
public void setUid(String uid) {
48+
mUid = uid;
49+
}
50+
51+
@ServerTimestamp
52+
public Date getTimestamp() {
53+
return mTimestamp;
54+
}
55+
56+
public void setTimestamp(Date timestamp) {
57+
mTimestamp = timestamp;
58+
}
59+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.firebase.uidemo.firestore;
2+
3+
import android.os.Bundle;
4+
import android.support.annotation.NonNull;
5+
import android.support.v7.app.AppCompatActivity;
6+
import android.support.v7.widget.LinearLayoutManager;
7+
import android.support.v7.widget.RecyclerView;
8+
import android.util.Log;
9+
import android.view.LayoutInflater;
10+
import android.view.View;
11+
import android.view.ViewGroup;
12+
import android.widget.Button;
13+
import android.widget.EditText;
14+
import android.widget.TextView;
15+
import android.widget.Toast;
16+
17+
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
18+
import com.firebase.uidemo.R;
19+
import com.firebase.uidemo.database.ChatHolder;
20+
import com.google.android.gms.tasks.OnCompleteListener;
21+
import com.google.android.gms.tasks.OnFailureListener;
22+
import com.google.android.gms.tasks.Task;
23+
import com.google.firebase.auth.FirebaseAuth;
24+
import com.google.firebase.firestore.DocumentReference;
25+
import com.google.firebase.firestore.FirebaseFirestore;
26+
import com.google.firebase.firestore.Query;
27+
28+
import butterknife.BindView;
29+
import butterknife.ButterKnife;
30+
import butterknife.OnClick;
31+
32+
/**
33+
* Class demonstrating a simple real-time chat app that relies on {@link FirestoreRecyclerAdapter}.
34+
*/
35+
public class FirestoreChatActivity extends AppCompatActivity implements FirebaseAuth.AuthStateListener {
36+
37+
private static final String TAG = "FirestoreChat";
38+
39+
@BindView(R.id.messagesList)
40+
RecyclerView mRecycler;
41+
42+
@BindView(R.id.sendButton)
43+
Button mSendButton;
44+
45+
@BindView(R.id.messageEdit)
46+
EditText mMessageEdit;
47+
48+
@BindView(R.id.emptyTextView)
49+
TextView mEmptyListMessage;
50+
51+
private FirebaseAuth mAuth;
52+
private FirebaseFirestore mFirestore;
53+
private FirestoreRecyclerAdapter<Chat, ChatHolder> mAdapter;
54+
55+
@Override
56+
protected void onCreate(Bundle savedInstanceState) {
57+
super.onCreate(savedInstanceState);
58+
setContentView(R.layout.activity_chat);
59+
ButterKnife.bind(this);
60+
61+
// Enable verbose Firestore logging
62+
FirebaseFirestore.setLoggingEnabled(true);
63+
64+
mAuth = FirebaseAuth.getInstance();
65+
mFirestore = FirebaseFirestore.getInstance();
66+
67+
// Get the last 50 chat messages, ordered by timestamp
68+
Query query = mFirestore.collection("chats").orderBy("timestamp").limit(50);
69+
70+
LinearLayoutManager manager = new LinearLayoutManager(this);
71+
mAdapter = new FirestoreRecyclerAdapter<Chat, ChatHolder>(query, Chat.class) {
72+
@Override
73+
public void onBindViewHolder(ChatHolder holder, int i, Chat model) {
74+
holder.bind(model);
75+
}
76+
77+
@Override
78+
public ChatHolder onCreateViewHolder(ViewGroup group, int i) {
79+
View view = LayoutInflater.from(group.getContext())
80+
.inflate(R.layout.message, group, false);
81+
82+
return new ChatHolder(view);
83+
}
84+
85+
@Override
86+
public void onDataChanged() {
87+
// If there are no chat messages, show a view that invites the user to add a message.
88+
mEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
89+
}
90+
};
91+
92+
mRecycler.setLayoutManager(manager);
93+
mRecycler.setAdapter(mAdapter);
94+
}
95+
96+
@Override
97+
public void onAuthStateChanged(@NonNull FirebaseAuth auth) {
98+
if (auth.getCurrentUser() != null) {
99+
mAdapter.startListening();
100+
mSendButton.setEnabled(true);
101+
} else {
102+
mAdapter.stopListening();
103+
mSendButton.setEnabled(false);
104+
}
105+
}
106+
107+
@Override
108+
protected void onStart() {
109+
super.onStart();
110+
111+
signInAnonymously();
112+
mAuth.addAuthStateListener(this);
113+
}
114+
115+
@Override
116+
protected void onStop() {
117+
super.onStop();
118+
119+
mAuth.removeAuthStateListener(this);
120+
mAdapter.stopListening();
121+
}
122+
123+
private void signInAnonymously() {
124+
if (mAuth.getCurrentUser() != null) {
125+
return;
126+
}
127+
128+
mAuth.signInAnonymously()
129+
.addOnFailureListener(this, new OnFailureListener() {
130+
@Override
131+
public void onFailure(@NonNull Exception e) {
132+
Log.w(TAG, "signIn:failure", e);
133+
Toast.makeText(FirestoreChatActivity.this,
134+
"Authentication failed.", Toast.LENGTH_LONG).show();
135+
}
136+
});
137+
}
138+
139+
@OnClick(R.id.sendButton)
140+
public void onSendClick() {
141+
String uid = mAuth.getCurrentUser().getUid();
142+
String name = "User " + uid.substring(0, 6);
143+
144+
Chat chat = new Chat(name, mMessageEdit.getText().toString(), uid);
145+
146+
mFirestore.collection("chats").add(chat)
147+
.addOnCompleteListener(this,
148+
new OnCompleteListener<DocumentReference>() {
149+
@Override
150+
public void onComplete(@NonNull Task<DocumentReference> task) {
151+
if (!task.isSuccessful()) {
152+
Log.e(TAG, "Failed to write message", task.getException());
153+
}
154+
}
155+
});
156+
157+
mMessageEdit.setText("");
158+
}
159+
}

app/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
<string name="app_name">Firebase UI</string>
33

44
<string name="name_chat">ChatActivity</string>
5+
<string name="name_firestore_chat">FirestoreChatActivity</string>
56
<string name="name_auth_ui">Auth UI demo</string>
67
<string name="name_image">Storage Image Demo</string>
78

89
<string name="desc_chat">Demonstrates using a FirebaseRecyclerAdapter to load data from Firebase Database into a RecyclerView for a basic chat app.</string>
10+
<string name="desc_firestore_chat">Demonstrates using a FirestoreRecyclerAdapter to load data from Cloud Firestore into a RecyclerView for a basic chat app.</string>
911
<string name="desc_auth_ui">Demonstrates the Firebase Auth UI flow, with customization options.</string>
1012
<string name="desc_image">Demonstrates displaying an image from Cloud Storage using Glide.</string>
1113

common/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

common/build.gradle

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
apply plugin: 'com.android.library'
2+
apply from: '../library/quality/quality.gradle'
3+
check.dependsOn 'compileDebugAndroidTestJavaWithJavac'
4+
5+
android {
6+
compileSdkVersion compileSdk
7+
buildToolsVersion buildTools
8+
9+
defaultConfig {
10+
minSdkVersion minSdk
11+
targetSdkVersion targetSdk
12+
versionCode 1
13+
versionName "1.0"
14+
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
15+
}
16+
17+
buildTypes {
18+
release {
19+
minifyEnabled false
20+
proguardFiles getDefaultProguardFile('proguard-android.txt')
21+
}
22+
}
23+
}
24+
25+
dependencies {
26+
compile "com.android.support:recyclerview-v7:$supportLibraryVersion"
27+
// Needed to override play services
28+
compile "com.android.support:support-v4:$supportLibraryVersion"
29+
}

common/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.google.firebase.firestore.common" />

0 commit comments

Comments
 (0)