Skip to content

Instantly share code, notes, and snippets.

@puf
Last active January 21, 2025 16:18

Revisions

  1. puf revised this gist Aug 1, 2016. 1 changed file with 34 additions and 0 deletions.
    34 changes: 34 additions & 0 deletions build.gradle
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,34 @@
    apply plugin: 'com.android.application'

    android {
    compileSdkVersion 24
    buildToolsVersion '24'

    defaultConfig {
    applicationId "com.google.firebase.zerotoapp"
    minSdkVersion 16
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    }
    buildTypes {
    release {
    minifyEnabled false
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    }
    }

    dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile 'com.android.support:design:24.0.0'
    compile 'com.android.support:recyclerview-v7:24.0.0'
    compile 'com.google.firebase:firebase-database:9.2.1'
    compile 'com.google.firebase:firebase-auth:9.2.1'
    compile 'com.google.firebase:firebase-storage:9.2.1'
    compile 'com.github.bumptech.glide:glide:3.7.0'
    compile 'com.firebaseui:firebase-ui-auth:0.4.3'
    }
    apply plugin: 'com.google.gms.google-services'
  2. puf revised this gist Jun 2, 2016. 1 changed file with 95 additions and 0 deletions.
    95 changes: 95 additions & 0 deletions activity_main.xml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,95 @@
    <?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>
  3. puf revised this gist May 26, 2016. 1 changed file with 60 additions and 2 deletions.
    62 changes: 60 additions & 2 deletions MainActivity.java
    Original file line number Diff line number Diff line change
    @@ -104,22 +104,80 @@ 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());
    adapter.addMessage(chat);
    // 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();

    messageTxt.setText(selectedImageUri.toString());
    // 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());
    }
    });
    }
    }
    }
  4. puf created this gist May 21, 2016.
    14 changes: 14 additions & 0 deletions ChatMessage.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,14 @@
    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;
    }
    }
    40 changes: 40 additions & 0 deletions ChatMessageAdapter.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,40 @@
    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();
    }
    }
    45 changes: 45 additions & 0 deletions ChatMessageViewHolder.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    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);
    }
    }
    }
    94 changes: 94 additions & 0 deletions LoginDialog.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,94 @@
    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();
    }
    }
    125 changes: 125 additions & 0 deletions MainActivity.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,125 @@
    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());
    }
    });

    sendBtn.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
    ChatMessage chat = new ChatMessage(username, messageTxt.getText().toString());
    adapter.addMessage(chat);
    messageTxt.setText("");
    }
    });

    }

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == RC_PHOTO_PICKER && resultCode == RESULT_OK) {
    Uri selectedImageUri = data.getData();

    messageTxt.setText(selectedImageUri.toString());
    }
    }
    }