Skip to content

Commit 4c194a9

Browse files
SUPERCILEXsamtstern
authored andcommitted
Revamp Firestore sample with new public repo changes (#4)
1 parent eab7d78 commit 4c194a9

File tree

6 files changed

+114
-95
lines changed

6 files changed

+114
-95
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
<!-- Firestore demo -->
4242
<activity
4343
android:name=".database.firestore.FirestoreChatActivity"
44-
android:label="@string/name_chat" />
44+
android:label="@string/title_firestore_activity" />
4545

4646
<!-- Realtime database demo -->
4747
<activity

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ private static class ActivityChooserAdapter extends RecyclerView.Adapter<Activit
5858

5959
private static final int[] DESCRIPTION_NAMES = new int[]{
6060
R.string.title_auth_activity,
61-
R.string.name_firestore_chat,
61+
R.string.title_firestore_activity,
6262
R.string.title_realtime_database_activity,
6363
R.string.title_storage_activity
6464
};
6565

6666
private static final int[] DESCRIPTION_IDS = new int[]{
6767
R.string.desc_auth,
68-
R.string.desc_firestore_chat,
68+
R.string.desc_firestore,
6969
R.string.desc_realtime_database,
7070
R.string.desc_storage
7171
};

app/src/main/java/com/firebase/uidemo/database/firestore/FirestoreChatActivity.java

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.os.Bundle;
44
import android.support.annotation.NonNull;
5-
import android.support.v7.app.AppCompatActivity;
65
import android.support.v7.widget.LinearLayoutManager;
76
import android.support.v7.widget.RecyclerView;
87
import android.util.Log;
@@ -14,15 +13,17 @@
1413
import android.widget.TextView;
1514
import android.widget.Toast;
1615

16+
import com.firebase.ui.auth.ui.ImeHelper;
1717
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
1818
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
1919
import com.firebase.uidemo.R;
2020
import com.firebase.uidemo.database.ChatHolder;
21-
import com.google.android.gms.tasks.OnCompleteListener;
21+
import com.firebase.uidemo.database.realtime.Chat;
22+
import com.firebase.uidemo.util.LifecycleActivity;
23+
import com.firebase.uidemo.util.SignInResultNotifier;
2224
import com.google.android.gms.tasks.OnFailureListener;
23-
import com.google.android.gms.tasks.Task;
2425
import com.google.firebase.auth.FirebaseAuth;
25-
import com.google.firebase.firestore.DocumentReference;
26+
import com.google.firebase.firestore.CollectionReference;
2627
import com.google.firebase.firestore.FirebaseFirestore;
2728
import com.google.firebase.firestore.Query;
2829

@@ -31,14 +32,28 @@
3132
import butterknife.OnClick;
3233

3334
/**
34-
* Class demonstrating a simple real-time chat app that relies on {@link FirestoreRecyclerAdapter}.
35+
* Class demonstrating how to setup a {@link RecyclerView} with an adapter while taking sign-in
36+
* states into consideration. Also demonstrates adding data to a ref and then reading it back using
37+
* the {@link FirestoreRecyclerAdapter} to build a simple chat app.
38+
* <p>
39+
* For a general intro to the RecyclerView, see <a href="https://developer.android.com/training/material/lists-cards.html">Creating
40+
* Lists</a>.
3541
*/
36-
public class FirestoreChatActivity extends AppCompatActivity implements FirebaseAuth.AuthStateListener {
42+
public class FirestoreChatActivity extends LifecycleActivity
43+
implements FirebaseAuth.AuthStateListener {
44+
private static final String TAG = "FirestoreChatActivity";
3745

38-
private static final String TAG = "FirestoreChat";
46+
private static final CollectionReference sChatCollection =
47+
FirebaseFirestore.getInstance().collection("chats");
48+
/** Get the last 50 chat messages ordered by timestamp . */
49+
private static final Query sChatQuery = sChatCollection.orderBy("timestamp").limit(50);
50+
51+
static {
52+
FirebaseFirestore.setLoggingEnabled(true);
53+
}
3954

4055
@BindView(R.id.messagesList)
41-
RecyclerView mRecycler;
56+
RecyclerView mRecyclerView;
4257

4358
@BindView(R.id.sendButton)
4459
Button mSendButton;
@@ -49,117 +64,110 @@ public class FirestoreChatActivity extends AppCompatActivity implements Firebase
4964
@BindView(R.id.emptyTextView)
5065
TextView mEmptyListMessage;
5166

52-
private FirebaseAuth mAuth;
53-
private FirebaseFirestore mFirestore;
54-
private FirestoreRecyclerAdapter<Chat, ChatHolder> mAdapter;
55-
5667
@Override
5768
protected void onCreate(Bundle savedInstanceState) {
5869
super.onCreate(savedInstanceState);
5970
setContentView(R.layout.activity_chat);
6071
ButterKnife.bind(this);
6172

62-
// Enable verbose Firestore logging
63-
FirebaseFirestore.setLoggingEnabled(true);
64-
65-
mAuth = FirebaseAuth.getInstance();
66-
mFirestore = FirebaseFirestore.getInstance();
67-
68-
// Get the last 50 chat messages, ordered by timestamp
69-
Query query = mFirestore.collection("chats").orderBy("timestamp").limit(50);
70-
71-
LinearLayoutManager manager = new LinearLayoutManager(this);
73+
mRecyclerView.setHasFixedSize(true);
74+
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
7275

73-
FirestoreRecyclerOptions<Chat> options = new FirestoreRecyclerOptions.Builder<Chat>()
74-
.setQuery(query, Chat.class)
75-
.build();
76-
77-
mAdapter = new FirestoreRecyclerAdapter<Chat, ChatHolder>(options) {
76+
ImeHelper.setImeOnDoneListener(mMessageEdit, new ImeHelper.DonePressedListener() {
7877
@Override
79-
public void onBindViewHolder(ChatHolder holder, int position, Chat model) {
80-
holder.bind(model);
81-
}
82-
83-
@Override
84-
public ChatHolder onCreateViewHolder(ViewGroup group, int i) {
85-
View view = LayoutInflater.from(group.getContext())
86-
.inflate(R.layout.message, group, false);
87-
88-
return new ChatHolder(view);
78+
public void onDonePressed() {
79+
onSendClick();
8980
}
81+
});
82+
}
9083

91-
@Override
92-
public void onDataChanged() {
93-
// If there are no chat messages, show a view that invites the user to add a message.
94-
mEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
95-
}
96-
};
84+
@Override
85+
public void onStart() {
86+
super.onStart();
87+
if (isSignedIn()) { attachRecyclerViewAdapter(); }
88+
FirebaseAuth.getInstance().addAuthStateListener(this);
89+
}
9790

98-
mRecycler.setLayoutManager(manager);
99-
mRecycler.setAdapter(mAdapter);
91+
@Override
92+
protected void onStop() {
93+
super.onStop();
94+
FirebaseAuth.getInstance().removeAuthStateListener(this);
10095
}
10196

10297
@Override
10398
public void onAuthStateChanged(@NonNull FirebaseAuth auth) {
104-
if (auth.getCurrentUser() != null) {
105-
mAdapter.startListening();
106-
mSendButton.setEnabled(true);
99+
mSendButton.setEnabled(isSignedIn());
100+
mMessageEdit.setEnabled(isSignedIn());
101+
102+
if (isSignedIn()) {
103+
attachRecyclerViewAdapter();
107104
} else {
108-
mAdapter.stopListening();
109-
mSendButton.setEnabled(false);
105+
Toast.makeText(this, R.string.signing_in, Toast.LENGTH_SHORT).show();
106+
auth.signInAnonymously().addOnCompleteListener(new SignInResultNotifier(this));
110107
}
111108
}
112109

113-
@Override
114-
protected void onStart() {
115-
super.onStart();
116-
117-
signInAnonymously();
118-
mAuth.addAuthStateListener(this);
110+
private boolean isSignedIn() {
111+
return FirebaseAuth.getInstance().getCurrentUser() != null;
119112
}
120113

121-
@Override
122-
protected void onStop() {
123-
super.onStop();
124-
125-
mAuth.removeAuthStateListener(this);
126-
mAdapter.stopListening();
127-
}
114+
private void attachRecyclerViewAdapter() {
115+
final RecyclerView.Adapter adapter = newAdapter();
128116

129-
private void signInAnonymously() {
130-
if (mAuth.getCurrentUser() != null) {
131-
return;
132-
}
117+
// Scroll to bottom on new messages
118+
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
119+
@Override
120+
public void onItemRangeInserted(int positionStart, int itemCount) {
121+
mRecyclerView.smoothScrollToPosition(adapter.getItemCount());
122+
}
123+
});
133124

134-
mAuth.signInAnonymously()
135-
.addOnFailureListener(this, new OnFailureListener() {
136-
@Override
137-
public void onFailure(@NonNull Exception e) {
138-
Log.w(TAG, "signIn:failure", e);
139-
Toast.makeText(FirestoreChatActivity.this,
140-
"Authentication failed.", Toast.LENGTH_LONG).show();
141-
}
142-
});
125+
mRecyclerView.setAdapter(adapter);
143126
}
144127

145128
@OnClick(R.id.sendButton)
146129
public void onSendClick() {
147-
String uid = mAuth.getCurrentUser().getUid();
130+
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
148131
String name = "User " + uid.substring(0, 6);
149132

150-
Chat chat = new Chat(name, mMessageEdit.getText().toString(), uid);
151-
152-
mFirestore.collection("chats").add(chat)
153-
.addOnCompleteListener(this,
154-
new OnCompleteListener<DocumentReference>() {
155-
@Override
156-
public void onComplete(@NonNull Task<DocumentReference> task) {
157-
if (!task.isSuccessful()) {
158-
Log.e(TAG, "Failed to write message", task.getException());
159-
}
160-
}
161-
});
133+
onAddMessage(new Chat(name, mMessageEdit.getText().toString(), uid));
162134

163135
mMessageEdit.setText("");
164136
}
137+
138+
protected RecyclerView.Adapter newAdapter() {
139+
FirestoreRecyclerOptions<Chat> options =
140+
new FirestoreRecyclerOptions.Builder<Chat>()
141+
.setQuery(sChatQuery, Chat.class)
142+
.setLifecycleOwner(this)
143+
.build();
144+
145+
return new FirestoreRecyclerAdapter<Chat, ChatHolder>(options) {
146+
@Override
147+
public ChatHolder onCreateViewHolder(ViewGroup parent, int viewType) {
148+
return new ChatHolder(LayoutInflater.from(parent.getContext())
149+
.inflate(R.layout.message, parent, false));
150+
}
151+
152+
@Override
153+
protected void onBindViewHolder(ChatHolder holder, int position, Chat model) {
154+
holder.bind(model);
155+
}
156+
157+
@Override
158+
public void onDataChanged() {
159+
// If there are no chat messages, show a view that invites the user to add a message.
160+
mEmptyListMessage.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
161+
}
162+
};
163+
}
164+
165+
protected void onAddMessage(Chat chat) {
166+
sChatCollection.add(chat).addOnFailureListener(this, new OnFailureListener() {
167+
@Override
168+
public void onFailure(@NonNull Exception e) {
169+
Log.e(TAG, "Failed to write message", e);
170+
}
171+
});
172+
}
165173
}

app/src/main/java/com/firebase/uidemo/database/realtime/RealtimeDbChatActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
* For a general intro to the RecyclerView, see <a href="https://developer.android.com/training/material/lists-cards.html">Creating
3939
* Lists</a>.
4040
*/
41-
public abstract class RealtimeDbChatActivity extends LifecycleActivity
41+
public class RealtimeDbChatActivity extends LifecycleActivity
4242
implements FirebaseAuth.AuthStateListener {
4343
private static final String TAG = "RealtimeDatabaseDemo";
4444

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33

44
<!-- Chooser -->
55
<string name="title_auth_activity">Auth UI demo</string>
6-
<string name="name_firestore_chat">FirestoreChatActivity</string>
6+
<string name="title_firestore_activity">FirestoreChatActivity</string>
77
<string name="title_realtime_database_activity">Real-time database demo</string>
88
<string name="title_storage_activity">Storage Image Demo</string>
99

1010
<string name="desc_auth">Demonstrates the Firebase Auth UI flow, with customization options.</string>
11+
<string name="desc_firestore">Demonstrates using a FirestoreRecyclerAdapter to load data from Cloud Firestore into a RecyclerView for a basic chat app.</string>
1112
<string name="desc_realtime_database">Demonstrates using a FirebaseRecyclerAdapter to load data from Firebase Database into a RecyclerView for a basic chat app.</string>
12-
<string name="desc_firestore_chat">Demonstrates using a FirestoreRecyclerAdapter to load data from Cloud Firestore into a RecyclerView for a basic chat app.</string>
1313
<string name="desc_storage">Demonstrates displaying an image from Cloud Storage using Glide.</string>
1414

1515
<!-- Auth UI -->

app/src/main/res/xml-v25/shortcuts.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@
1111
android:targetClass="com.firebase.uidemo.auth.AuthUiActivity"/>
1212
</shortcut>
1313

14+
<shortcut
15+
android:shortcutId="firestore"
16+
android:enabled="true"
17+
android:icon="@mipmap/ic_launcher"
18+
android:shortcutShortLabel="@string/title_firestore_activity">
19+
<intent
20+
android:action="android.intent.action.VIEW"
21+
android:targetPackage="com.firebase.uidemo"
22+
android:targetClass="com.firebase.uidemo.database.firestore.FirestoreChatActivity"/>
23+
</shortcut>
24+
1425
<shortcut
1526
android:shortcutId="realtime-database"
1627
android:enabled="true"

0 commit comments

Comments
 (0)