-
-
Save Isabellle/fc082d4387c526e1919aff72129b8b17 to your computer and use it in GitHub Desktop.
Zero to App: Develop with Firebase (for Android - Google I/O 2016)
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
<?xml version="1.0" encoding="utf-8"?> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:paddingBottom="@dimen/activity_vertical_margin" | |
android:paddingLeft="@dimen/activity_horizontal_margin" | |
android:paddingRight="@dimen/activity_horizontal_margin" | |
android:paddingTop="@dimen/activity_vertical_margin" | |
tools:context="com.google.firebase.zerotoapp.MainActivity"> | |
<RelativeLayout | |
android:orientation="horizontal" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:id="@+id/header" | |
android:gravity="end"> | |
<ImageView | |
android:layout_width="36dp" | |
android:layout_height="36dp" | |
android:background="@drawable/ic_account_box_black_24dp" | |
android:id="@+id/userIcon" | |
android:foregroundGravity="center" | |
android:layout_alignParentStart="true" | |
android:layout_alignParentLeft="true" /> | |
<TextView | |
android:layout_width="141dp" | |
android:layout_height="wrap_content" | |
android:id="@+id/usernameTxt" | |
android:layout_toRightOf="@+id/userIcon" | |
android:layout_alignTop="@+id/userIcon" | |
android:layout_alignBottom="@+id/userIcon" | |
android:gravity="center_vertical" | |
tools:text="Username" | |
android:layout_weight="0" /> | |
<Button | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="Sign in" | |
android:id="@+id/loginBtn" | |
android:layout_alignParentEnd="true" | |
android:layout_alignParentRight="true" /> | |
<Button | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="Sign out" | |
android:id="@+id/logoutBtn" | |
android:layout_alignParentEnd="true" | |
android:layout_alignParentRight="true" /> | |
</RelativeLayout> | |
<android.support.v7.widget.RecyclerView | |
android:id="@+id/messagesList" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:layout_alignParentLeft="true" | |
android:layout_alignParentStart="true" | |
tools:listitem="@android:layout/two_line_list_item" | |
android:layout_above="@+id/footer" | |
android:layout_below="@+id/header" /> | |
<LinearLayout | |
android:orientation="horizontal" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:layout_alignParentBottom="true" | |
android:layout_alignParentLeft="true" | |
android:layout_alignParentStart="true" | |
android:id="@+id/footer"> | |
<ImageButton | |
android:layout_width="36dp" | |
android:layout_height="36dp" | |
android:id="@+id/imageBtn" | |
android:background="@android:drawable/ic_menu_gallery" /> | |
<EditText | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:id="@+id/messageTxt" | |
android:layout_gravity="bottom" | |
android:layout_weight="1" | |
android:inputType="textShortMessage|textAutoCorrect" /> | |
<Button | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="Send" | |
android:id="@+id/sendBtn" | |
android:layout_gravity="bottom" /> | |
</LinearLayout> | |
</RelativeLayout> |
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
package com.google.firebase.zerotoapp; | |
public class ChatMessage { | |
public String name; | |
public String message; | |
public ChatMessage() { | |
} | |
public ChatMessage(String name, String message) { | |
this.name = name; | |
this.message = message; | |
} | |
} |
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
package com.google.firebase.zerotoapp; | |
import android.app.Activity; | |
import android.support.v7.widget.RecyclerView; | |
import android.util.Log; | |
import android.view.ViewGroup; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class ChatMessageAdapter extends RecyclerView.Adapter<ChatMessageViewHolder> { | |
private static final String TAG = "ChatMessageAdapter"; | |
private final Activity activity; | |
List<ChatMessage> messages = new ArrayList<>(); | |
public ChatMessageAdapter(Activity activity) { | |
this.activity = activity; | |
} | |
public void addMessage(ChatMessage chat) { | |
messages.add(chat); | |
notifyItemInserted(messages.size()); | |
} | |
@Override | |
public ChatMessageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |
return new ChatMessageViewHolder(activity, activity.getLayoutInflater().inflate(android.R.layout.two_line_list_item, parent, false)); | |
} | |
@Override | |
public void onBindViewHolder(ChatMessageViewHolder holder, int position) { | |
holder.bind(messages.get(position)); | |
} | |
@Override | |
public int getItemCount() { | |
return messages.size(); | |
} | |
} |
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
package com.google.firebase.zerotoapp; | |
import android.app.Activity; | |
import android.support.v7.widget.RecyclerView; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import com.bumptech.glide.Glide; | |
public class ChatMessageViewHolder extends RecyclerView.ViewHolder { | |
private static final String TAG = "ChatMessageViewHolder"; | |
private final Activity activity; | |
TextView name, message; | |
ImageView image; | |
public ChatMessageViewHolder(Activity activity, View itemView) { | |
super(itemView); | |
this.activity = activity; | |
name = (TextView) itemView.findViewById(android.R.id.text1); | |
message = (TextView) itemView.findViewById(android.R.id.text2); | |
image= new ImageView(activity); | |
((ViewGroup)itemView).addView(image); | |
} | |
public void bind(ChatMessage chat) { | |
name.setText(chat.name); | |
if (chat.message.startsWith("https://firebasestorage.googleapis.com/") || chat.message.startsWith("content://")) { | |
message.setVisibility(View.INVISIBLE); | |
image.setVisibility(View.VISIBLE); | |
Glide.with(activity) | |
.load(chat.message) | |
.into(image); | |
} | |
else { | |
message.setVisibility(View.VISIBLE); | |
image.setVisibility(View.GONE); | |
message.setText(chat.message); | |
} | |
} | |
} |
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
package com.google.firebase.zerotoapp; | |
import android.app.Activity; | |
import android.content.DialogInterface; | |
import android.support.v7.app.AlertDialog; | |
import android.text.InputType; | |
import android.widget.EditText; | |
import android.widget.LinearLayout; | |
import com.google.android.gms.tasks.OnCompleteListener; | |
import com.google.android.gms.tasks.OnSuccessListener; | |
import com.google.android.gms.tasks.Task; | |
import com.google.firebase.FirebaseApp; | |
import com.google.firebase.auth.AuthResult; | |
import com.google.firebase.auth.FirebaseAuth; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class LoginDialog { | |
private static final String TAG = "LoginDialog"; | |
static List<OnSuccessListener<EmailPasswordResult>> callbacks = new ArrayList<>(); | |
public static void onCredentials(final OnSuccessListener<EmailPasswordResult> callback) { | |
callbacks.add(callback); | |
} | |
public static class EmailPasswordResult { | |
public String email; | |
public String password; | |
public EmailPasswordResult() { | |
} | |
public EmailPasswordResult(String email, String password) { | |
this.email = email; | |
this.password = password; | |
} | |
} | |
public static void showLoginPrompt(final Activity activity, final FirebaseApp app) { | |
showLoginPrompt(activity, app, null); | |
} | |
public static void showLoginPrompt(final Activity activity, final FirebaseApp app, final OnSuccessListener<EmailPasswordResult> callback) { | |
AlertDialog.Builder builder = new AlertDialog.Builder(activity); | |
builder.setTitle("What's your username"); | |
LinearLayout parent = new LinearLayout(activity); | |
parent.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); | |
parent.setOrientation(LinearLayout.VERTICAL); | |
final EditText email = new EditText(activity); | |
email.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); | |
email.setHint("User name"); | |
parent.addView(email); | |
final EditText password = new EditText(activity); | |
password.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); | |
password.setHint("Password"); | |
parent.addView(password); | |
builder.setView(parent); | |
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
FirebaseAuth.getInstance(app).createUserWithEmailAndPassword(email.getText().toString(), password.getText().toString()) | |
.addOnCompleteListener(activity, new OnCompleteListener<AuthResult>() { | |
public void onComplete(Task<AuthResult> task) { | |
EmailPasswordResult result = new EmailPasswordResult(email.getText().toString(), password.getText().toString()); | |
if (callback != null) { | |
callback.onSuccess(result); | |
} | |
else { | |
for (OnSuccessListener<EmailPasswordResult> callback: callbacks){ | |
callback.onSuccess(result); | |
} | |
} | |
} | |
}); | |
dialog.dismiss(); | |
} | |
}); | |
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { | |
@Override | |
public void onClick(DialogInterface dialog, int which) { | |
dialog.cancel(); | |
} | |
}); | |
builder.show(); | |
} | |
} |
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
package com.google.firebase.zerotoapp; | |
import android.content.Intent; | |
import android.net.Uri; | |
import android.os.Bundle; | |
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.View; | |
import android.widget.Button; | |
import android.widget.EditText; | |
import android.widget.ImageButton; | |
import android.widget.TextView; | |
import com.google.android.gms.tasks.OnSuccessListener; | |
import com.google.firebase.FirebaseApp; | |
import com.google.firebase.auth.FirebaseAuth; | |
import com.google.firebase.database.DatabaseReference; | |
import com.google.firebase.database.FirebaseDatabase; | |
import com.google.firebase.storage.FirebaseStorage; | |
import com.google.firebase.storage.StorageReference; | |
public class MainActivity extends AppCompatActivity { | |
private static final String TAG = "MainActivity"; | |
static final int RC_PHOTO_PICKER = 1; | |
private Button sendBtn; | |
private EditText messageTxt; | |
private RecyclerView messagesList; | |
private ChatMessageAdapter adapter; | |
private ImageButton imageBtn; | |
private TextView usernameTxt; | |
private View loginBtn; | |
private View logoutBtn; | |
private FirebaseApp app; | |
private FirebaseDatabase database; | |
private FirebaseAuth auth; | |
private FirebaseStorage storage; | |
private DatabaseReference databaseRef; | |
private StorageReference storageRef; | |
private String username; | |
private void setUsername(String username) { | |
Log.d(TAG, "setUsername("+String.valueOf(username)+")"); | |
if (username == null) { | |
username = "Android"; | |
} | |
boolean isLoggedIn = !username.equals("Android"); | |
this.username = username; | |
this.usernameTxt.setText(username); | |
this.logoutBtn.setVisibility(isLoggedIn ? View.VISIBLE : View.GONE); | |
this.loginBtn .setVisibility(isLoggedIn ? View.GONE : View.VISIBLE); | |
} | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
sendBtn = (Button) findViewById(R.id.sendBtn); | |
messageTxt = (EditText) findViewById(R.id.messageTxt); | |
messagesList = (RecyclerView) findViewById(R.id.messagesList); | |
imageBtn = (ImageButton) findViewById(R.id.imageBtn); | |
loginBtn = findViewById(R.id.loginBtn); | |
logoutBtn = findViewById(R.id.logoutBtn); | |
usernameTxt = (TextView) findViewById(R.id.usernameTxt); | |
setUsername("Android"); | |
LinearLayoutManager layoutManager = new LinearLayoutManager(this); | |
messagesList.setHasFixedSize(false); | |
messagesList.setLayoutManager(layoutManager); | |
// Show an image picker when the user wants to upload an imasge | |
imageBtn.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
Intent intent = new Intent(Intent.ACTION_GET_CONTENT); | |
intent.setType("image/jpeg"); | |
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); | |
startActivityForResult(Intent.createChooser(intent, "Complete action using"), RC_PHOTO_PICKER); | |
} | |
}); | |
// Show a popup when the user asks to sign in | |
loginBtn.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
LoginDialog.showLoginPrompt(MainActivity.this, app); | |
} | |
}); | |
// Allow the user to sign out | |
logoutBtn.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
auth.signOut(); | |
} | |
}); | |
adapter = new ChatMessageAdapter(this); | |
messagesList.setAdapter(adapter); | |
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { | |
public void onItemRangeInserted(int positionStart, int itemCount) { | |
messagesList.smoothScrollToPosition(adapter.getItemCount()); | |
} | |
}); | |
// Get the Firebase app and all primitives we'll use | |
app = FirebaseApp.getInstance(); | |
database = FirebaseDatabase.getInstance(app); | |
auth = FirebaseAuth.getInstance(app); | |
storage = FirebaseStorage.getInstance(app); | |
// Get a reference to our chat "room" in the database | |
databaseRef = database.getReference("chat"); | |
sendBtn.setOnClickListener(new View.OnClickListener() { | |
public void onClick(View v) { | |
ChatMessage chat = new ChatMessage(username, messageTxt.getText().toString()); | |
// Push the chat message to the database | |
databaseRef.push().setValue(chat); | |
messageTxt.setText(""); | |
} | |
}); | |
// Listen for when child nodes get added to the collection | |
databaseRef.addChildEventListener(new ChildEventListener() { | |
public void onChildAdded(DataSnapshot snapshot, String s) { | |
// Get the chat message from the snapshot and add it to the UI | |
ChatMessage chat = snapshot.getValue(ChatMessage.class); | |
adapter.addMessage(chat); | |
} | |
public void onChildChanged(DataSnapshot dataSnapshot, String s) { } | |
public void onChildRemoved(DataSnapshot dataSnapshot) { } | |
public void onChildMoved(DataSnapshot dataSnapshot, String s) { } | |
public void onCancelled(DatabaseError databaseError) { } | |
}); | |
// When the user has entered credentials in the login dialog | |
LoginDialog.onCredentials(new OnSuccessListener<LoginDialog.EmailPasswordResult>() { | |
public void onSuccess(LoginDialog.EmailPasswordResult result) { | |
// Sign the user in with the email address and password they entered | |
auth.signInWithEmailAndPassword(result.email, result.password); | |
} | |
}); | |
// When the user signs in or out, update the username we keep for them | |
auth.addAuthStateListener(new FirebaseAuth.AuthStateListener() { | |
public void onAuthStateChanged(FirebaseAuth firebaseAuth) { | |
if (firebaseAuth.getCurrentUser() != null) { | |
// User signed in, set their email address as the user name | |
setUsername(firebaseAuth.getCurrentUser().getEmail()); | |
} | |
else { | |
// User signed out, set a default username | |
setUsername("Android"); | |
} | |
} | |
}); | |
} | |
public void onActivityResult(int requestCode, int resultCode, Intent data) { | |
if (requestCode == RC_PHOTO_PICKER && resultCode == RESULT_OK) { | |
Uri selectedImageUri = data.getData(); | |
// Get a reference to the location where we'll store our photos | |
storageRef = storage.getReference("chat_photos"); | |
// Get a reference to store file at chat_photos/<FILENAME> | |
final StorageReference photoRef = storageRef.child(selectedImageUri.getLastPathSegment()); | |
// Upload file to Firebase Storage | |
photoRef.putFile(selectedImageUri) | |
.addOnSuccessListener(this, new OnSuccessListener<UploadTask.TaskSnapshot>() { | |
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { | |
// When the image has successfully uploaded, we get its download URL | |
Uri downloadUrl = taskSnapshot.getDownloadUrl(); | |
// Set the download URL to the message box, so that the user can send it to the database | |
messageTxt.setText(downloadUrl.toString()); | |
} | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment