diff --git a/app/build.gradle b/app/build.gradle
index 113f182b5..0eb2276ef 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,5 @@
apply plugin: 'com.android.application'
+apply plugin: 'com.google.gms.google-services'
repositories {
mavenLocal()
@@ -8,13 +9,13 @@ repositories {
}
android {
- compileSdkVersion 24
- buildToolsVersion "24.0.1"
+ compileSdkVersion 28
+ buildToolsVersion "29.0.0"
defaultConfig {
applicationId "com.google.firebase.udacity.friendlychat"
minSdkVersion 16
- targetSdkVersion 24
+ targetSdkVersion 28
versionCode 1
versionName "1.0"
}
@@ -32,12 +33,22 @@ android {
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- testCompile 'junit:junit:4.12'
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'com.google.firebase:firebase-database:16.0.4'
+ implementation 'com.google.firebase:firebase-storage:16.0.4'
+ implementation 'com.google.firebase:firebase-auth:16.0.5'
+ implementation 'com.google.firebase:firebase-messaging:17.3.4'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
- compile 'com.android.support:design:24.2.0'
- compile 'com.android.support:appcompat-v7:24.2.0'
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
// Displaying images
- compile 'com.github.bumptech.glide:glide:3.6.1'
-}
\ No newline at end of file
+ implementation 'com.github.bumptech.glide:glide:4.10.0'
+ annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'
+
+ // Firebase UI Implimentation
+ implementation 'com.firebaseui:firebase-ui-auth:4.3.1'
+
+
+}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index bcd0e213c..0ac0fbcb7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
+
diff --git a/app/src/main/java/com/google/firebase/udacity/friendlychat/MainActivity.java b/app/src/main/java/com/google/firebase/udacity/friendlychat/MainActivity.java
index b9b486cd1..69458cfbf 100644
--- a/app/src/main/java/com/google/firebase/udacity/friendlychat/MainActivity.java
+++ b/app/src/main/java/com/google/firebase/udacity/friendlychat/MainActivity.java
@@ -15,8 +15,9 @@
*/
package com.google.firebase.udacity.friendlychat;
+import android.content.Intent;
+import android.net.Uri;
import android.os.Bundle;
-import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.InputFilter;
import android.text.TextWatcher;
@@ -29,16 +30,43 @@
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
+
+import com.firebase.ui.auth.AuthUI;
+import com.firebase.ui.auth.IdpResponse;
+import com.google.android.gms.tasks.Continuation;
+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.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.database.ChildEventListener;
+import com.google.firebase.database.DataSnapshot;
+import com.google.firebase.database.DatabaseError;
+import com.google.firebase.database.DatabaseReference;
+import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.database.annotations.Nullable;
+import com.google.firebase.storage.FirebaseStorage;
+import com.google.firebase.storage.StorageReference;
+import com.google.firebase.storage.UploadTask;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
- private static final String TAG = "MainActivity";
-
public static final String ANONYMOUS = "anonymous";
public static final int DEFAULT_MSG_LENGTH_LIMIT = 1000;
+ private static final String TAG = "MainActivity";
+
+
+ private static final int RC_SIGN_IN = 1;
+ private static final int RC_PHOTO_PICKER = 2;
private ListView mMessageListView;
private MessageAdapter mMessageAdapter;
@@ -46,9 +74,16 @@ public class MainActivity extends AppCompatActivity {
private ImageButton mPhotoPickerButton;
private EditText mMessageEditText;
private Button mSendButton;
-
private String mUsername;
+ private FirebaseDatabase mFirebaseDatabase;
+ private DatabaseReference mMessagesDatabaseReference;
+ private ChildEventListener mChildEventListener;
+ private FirebaseAuth mFirebaseAuth;
+ private FirebaseAuth.AuthStateListener mAuthStateListener;
+ private FirebaseStorage mFirebaseStorage;
+ private StorageReference mChatPhotosStorageReference;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -56,6 +91,16 @@ protected void onCreate(Bundle savedInstanceState) {
mUsername = ANONYMOUS;
+
+ // Initialize Firebase components
+ mFirebaseDatabase = FirebaseDatabase.getInstance();
+ mFirebaseAuth = FirebaseAuth.getInstance();
+ mFirebaseStorage = FirebaseStorage.getInstance();
+
+ mMessagesDatabaseReference = mFirebaseDatabase.getReference().child("messages");
+ mChatPhotosStorageReference = mFirebaseStorage.getReference().child("chat_photos");
+
+
// Initialize references to views
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mMessageListView = (ListView) findViewById(R.id.messageListView);
@@ -75,7 +120,10 @@ protected void onCreate(Bundle savedInstanceState) {
mPhotoPickerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- // TODO: Fire an intent to show an image picker
+ 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);
}
});
@@ -105,11 +153,110 @@ public void afterTextChanged(Editable editable) {
@Override
public void onClick(View view) {
// TODO: Send messages on click
+ // Send messages on click
+ FriendlyMessage friendlyMessage = new FriendlyMessage(mMessageEditText.getText().toString(), mUsername, null);
+ mMessagesDatabaseReference.push().setValue(friendlyMessage);
// Clear input box
mMessageEditText.setText("");
}
});
+
+
+ mAuthStateListener = new FirebaseAuth.AuthStateListener() {
+ @Override
+ public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
+ FirebaseUser user = firebaseAuth.getCurrentUser();
+ if (user != null) {
+ onSignedInInitialize(user.getDisplayName());
+ } else {
+ onSignOutCleanup();
+ startActivityForResult(
+ AuthUI.getInstance()
+ .createSignInIntentBuilder()
+ .setIsSmartLockEnabled(false)
+ .setAvailableProviders(Arrays.asList(
+ new AuthUI.IdpConfig.GoogleBuilder().build(),
+ new AuthUI.IdpConfig.EmailBuilder().build(),
+ new AuthUI.IdpConfig.PhoneBuilder().build()))
+ .build(),
+ RC_SIGN_IN);
+ }
+ }
+ };
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, @androidx.annotation.Nullable Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+
+ switch (requestCode) {
+ case RC_SIGN_IN:
+ if (resultCode == RESULT_OK) {
+ Toast.makeText(this, "Signed in!", Toast.LENGTH_SHORT).show();
+ } else if (resultCode == RESULT_CANCELED) {
+ Toast.makeText(this, "Sign in canceled", Toast.LENGTH_SHORT).show();
+ finish();
+ }
+ break;
+ case RC_PHOTO_PICKER:
+ if (resultCode == RESULT_OK) {
+ Toast.makeText(this, "picker in!", Toast.LENGTH_SHORT).show();
+ Uri selectedImageUri = data.getData();
+
+ // Get a reference to store file at chat_photos/
+ final StorageReference photoRef = mChatPhotosStorageReference.child(selectedImageUri.getLastPathSegment());
+
+ // Upload file to Firebase Storage
+ photoRef.putFile(selectedImageUri)
+ .continueWithTask(new Continuation>() {
+ @Override
+ public Task then(@NonNull Task task) throws Exception {
+ if (!task.isSuccessful()) {
+ throw task.getException();
+ }
+
+ // Continue with the task to get the download URL
+ return photoRef.getDownloadUrl();
+ }
+ }).addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ Uri downloadUri = task.getResult();
+ FriendlyMessage friendlyMessage = new FriendlyMessage(null, mUsername, downloadUri.toString());
+ mMessagesDatabaseReference.push().setValue(friendlyMessage);
+ } else {
+ // Handle failures
+ // ...
+ }
+ }
+ });
+ }
+ break;
+
+ default:
+ Toast.makeText(this, "Something Wrong", Toast.LENGTH_SHORT).show();
+ break;
+ }
+ }
+
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mFirebaseAuth.addAuthStateListener(mAuthStateListener);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (mAuthStateListener != null) {
+ mFirebaseAuth.removeAuthStateListener(mAuthStateListener);
+ }
+ detachDatabaseReadListener();
+ mMessageAdapter.clear();
}
@Override
@@ -121,6 +268,67 @@ public boolean onCreateOptionsMenu(Menu menu) {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- return super.onOptionsItemSelected(item);
+ switch (item.getItemId()) {
+ case R.id.sign_out_menu:
+ AuthUI.getInstance().signOut(this);
+ return true;
+
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void onSignedInInitialize(String username) {
+ mUsername = username;
+ attachDatabaseReadListener();
+
+ }
+
+ private void onSignOutCleanup() {
+ mUsername = ANONYMOUS;
+ mMessageAdapter.clear();
+ detachDatabaseReadListener();
+
+ }
+
+
+ private void attachDatabaseReadListener() {
+ if (mChildEventListener == null) {
+ mChildEventListener = new ChildEventListener() {
+ @Override
+ public void onChildAdded(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
+ FriendlyMessage friendlyMessage = dataSnapshot.getValue(FriendlyMessage.class);
+ mMessageAdapter.add(friendlyMessage);
+ }
+
+ @Override
+ public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
+
+ }
+
+ @Override
+ public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
+
+ }
+
+ @Override
+ public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {
+
+ }
+
+ @Override
+ public void onCancelled(@NonNull DatabaseError databaseError) {
+
+ }
+ };
+ mMessagesDatabaseReference.addChildEventListener(mChildEventListener);
+ }
+ }
+
+ private void detachDatabaseReadListener() {
+ if (mChildEventListener != null) {
+ mMessagesDatabaseReference.removeEventListener(mChildEventListener);
+ mChildEventListener = null;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8bf7fbac7..a4dac53e2 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,4 +2,6 @@
Friendly Chat
Sign Out
Send
+
+
diff --git a/build.gradle b/build.gradle
index 67fa30cbc..cded88118 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,12 +4,17 @@ buildscript {
repositories {
jcenter()
mavenLocal()
+ google()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.2.2'
+ classpath 'com.android.tools.build:gradle:3.5.0'
+ classpath "io.realm:realm-gradle-plugin:6.0.0"
+ classpath 'com.google.firebase:firebase-auth:16.0.5'
+ classpath 'com.google.gms:google-services:4.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
+
}
}
@@ -23,3 +28,12 @@ allprojects {
task clean(type: Delete) {
delete rootProject.buildDir
}
+
+
+allprojects {
+ repositories {
+ jcenter()
+ maven { url 'https://maven.google.com' }
+ google()
+ }
+}
diff --git a/gradle.properties b/gradle.properties
index 1d3591c8a..915f0e66f 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,4 +15,6 @@
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
\ No newline at end of file
+# org.gradle.parallel=true
+android.enableJetifier=true
+android.useAndroidX=true
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index ce88022b7..f0be5ac14 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Tue Aug 16 17:43:49 PDT 2016
+#Wed Oct 16 11:08:18 BDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip