diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..39fb081 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 0000000..96cc43e --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 0000000..e7bedf3 --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..adb61ad --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..5d19981 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8a3e2ed --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 4a040e1..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -Repository for MDB Training Program Mini-Project Submissions - -Finalized mini-projects should be stored in personal portfolios, but this repository will be used for providing feedback on code quality using the GitHub code review features. - -When pushing code to this repo, DO NOT push to master. Create a new branch and open a pull request. \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..037bbde --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,41 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 24 + buildToolsVersion "24.0.2" + defaultConfig { + applicationId "mdb.project3.mdbevents" + minSdkVersion 14 + targetSdkVersion 24 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:24.2.1' + testCompile 'junit:junit:4.12' + compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha9' + compile 'com.android.support:design:24.2.1' + compile 'com.rengwuxian.materialedittext:library:2.1.4' + compile 'com.google.firebase:firebase-auth:9.6.1' + compile 'com.google.firebase:firebase-database:9.6.1' + compile 'com.google.firebase:firebase-storage:9.6.1' + compile 'com.android.support:cardview-v7:24.+' + compile 'com.github.bumptech.glide:glide:3.7.0' + compile 'com.android.support:palette-v7:24.2.1' +} + +apply plugin: 'com.google.gms.google-services' + diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..a72036d --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,42 @@ +{ + "project_info": { + "project_number": "420424174481", + "firebase_url": "https://mdb-events.firebaseio.com", + "project_id": "mdb-events", + "storage_bucket": "mdb-events.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:420424174481:android:616bf578be97dd79", + "android_client_info": { + "package_name": "mdb.project3.mdbevents" + } + }, + "oauth_client": [ + { + "client_id": "420424174481-i3hcls6241kocqompn743j82tud7pkf8.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyC9zQX9VAp0wG7G1KIaxMeK79NUZZGqQ94" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 1, + "other_platform_oauth_client": [] + }, + "ads_service": { + "status": 2 + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..37e7156 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\Ma\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/mdb/project3/mdbevents/ExampleInstrumentedTest.java b/app/src/androidTest/java/mdb/project3/mdbevents/ExampleInstrumentedTest.java new file mode 100644 index 0000000..17de412 --- /dev/null +++ b/app/src/androidTest/java/mdb/project3/mdbevents/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package mdb.project3.mdbevents; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("mdb.project3.mdbevents", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a0d0841 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/cornerstone.ttf b/app/src/main/assets/fonts/cornerstone.ttf new file mode 100644 index 0000000..3bffcc6 Binary files /dev/null and b/app/src/main/assets/fonts/cornerstone.ttf differ diff --git a/app/src/main/java/mdb/project3/mdbevents/CreateSocial.java b/app/src/main/java/mdb/project3/mdbevents/CreateSocial.java new file mode 100644 index 0000000..74bfc32 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/CreateSocial.java @@ -0,0 +1,211 @@ +package mdb.project3.mdbevents; + +import android.app.DatePickerDialog; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Typeface; +import android.net.Uri; +import android.provider.MediaStore; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.AppCompatButton; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.DatePicker; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; +import com.google.firebase.storage.UploadTask; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; + +public class CreateSocial extends AppCompatActivity implements View.OnClickListener { + + private final int PICK_IMAGE_REQUEST = 1; + + private DatePickerDialog.OnDateSetListener dateSetListener; + private EditText date, socialName, socialDescription; + private TextView createSocialTitle; + private ImageButton socialPictureView; + private Calendar myCalendar = Calendar.getInstance(); + private boolean updatedPicture = false; + private AppCompatButton createSocialButton; + private Bitmap socialImage; + + private DatabaseReference dbRef; + private FirebaseAuth mAuth; + private FirebaseStorage mStorage; + + private Toast mToast; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create_social); + + bindDateSetListeners(); + bindViews(); + + dbRef = FirebaseDatabase.getInstance().getReference(); + mStorage = FirebaseStorage.getInstance(); + mAuth = FirebaseAuth.getInstance(); + } + + private void bindViews() { + date = (EditText) findViewById(R.id.date); + createSocialTitle = (TextView) findViewById(R.id.new_social_title); + socialName = (EditText) findViewById(R.id.name_of_social); + socialDescription = (EditText) findViewById(R.id.social_description); + socialPictureView = (ImageButton) findViewById(R.id.social_image); + createSocialButton = (AppCompatButton) findViewById(R.id.create_social_button); + + Typeface customFont = Typeface.createFromAsset(getAssets(), "fonts/cornerstone.ttf"); + createSocialTitle.setTypeface(customFont); + + date.setOnClickListener(this); + socialPictureView.setOnClickListener(this); + createSocialButton.setOnClickListener(this); + } + + private void bindDateSetListeners() { + dateSetListener = new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) { + date.setText(new StringBuilder() + .append(month + 1).append("/") + .append(dayOfMonth).append("/") + .append(year)); + } + }; + } + + private void updateDatabase() { + if (!validate()) + return; + + mToast = Toast.makeText(getApplicationContext(), "Creating event...", Toast.LENGTH_LONG); + mToast.show(); + + FirebaseUser user = mAuth.getCurrentUser(); + if (user == null) { + Toast.makeText(getApplicationContext(), "Session timed out!", Toast.LENGTH_SHORT).show(); + startActivity(new Intent(getApplicationContext(), MainActivity.class)); + } else { + final String dbKey = dbRef.child("Events").push().getKey(); + final String name = socialName.getText().toString(); + final String emailAddress = user.getEmail(); + final int numInterested = 0; + final String timeStamp = String.valueOf(myCalendar.getTimeInMillis() / 1000L); + final String dateString = date.getText().toString(); + final String description = socialDescription.getText().toString(); + + StorageReference storageReference = mStorage.getReferenceFromUrl("gs://mdb-events.appspot.com/"); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + socialImage.compress(Bitmap.CompressFormat.JPEG, 100, baos); + byte[] data = baos.toByteArray(); + UploadTask uploadTask = storageReference.child("images/" + dbKey + ".jpg").putBytes(data); + uploadTask.addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + Toast.makeText(getApplicationContext(), "Creating a new social failed!", Toast.LENGTH_SHORT).show(); + } + }).addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { + Uri downloadUri = taskSnapshot.getDownloadUrl(); + dbRef.child("Events").child(dbKey).setValue(new Event(name, + emailAddress, numInterested, downloadUri.toString(), timeStamp, description, + dateString, new ArrayList())); + startActivity(new Intent(CreateSocial.this, FeedActivity.class)); + } + }); + } + } + + private boolean validate() { + boolean emptyFields = TextUtils.isEmpty(socialName.getText().toString()) || + TextUtils.isEmpty(socialDescription.getText().toString()) || + TextUtils.isEmpty(date.getText().toString()); + boolean valid = !emptyFields && updatedPicture; + if (!valid) { + Snackbar.make(findViewById(R.id.activity_create_social), + "Required fields are empty", + Snackbar.LENGTH_SHORT).show(); + } + return valid; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mToast != null) + mToast.cancel(); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.date: + new DatePickerDialog(CreateSocial.this, + dateSetListener, + myCalendar.get(Calendar.YEAR), + myCalendar.get(Calendar.MONTH), + myCalendar.get(Calendar.DAY_OF_MONTH)) + .show(); + break; + case R.id.social_image: + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(Intent.createChooser(intent, "Select Image"), PICK_IMAGE_REQUEST); + break; + case R.id.create_social_button: + updateDatabase(); + break; + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == PICK_IMAGE_REQUEST && + resultCode == RESULT_OK && + data != null && + data.getData() != null) { + Uri uri = data.getData(); + try { + socialImage = MediaStore.Images.Media.getBitmap(getContentResolver(), uri); + if (socialImage.getWidth() > socialPictureView.getWidth()) { + int newHeight = (socialImage.getHeight() * socialPictureView.getWidth()) / socialImage.getWidth(); + socialPictureView.setImageBitmap( + Bitmap.createScaledBitmap(socialImage, socialPictureView.getWidth(), newHeight, false)); + } else { + socialPictureView.setImageBitmap(socialImage); + } + + updatedPicture = true; + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/app/src/main/java/mdb/project3/mdbevents/DetailActivity.java b/app/src/main/java/mdb/project3/mdbevents/DetailActivity.java new file mode 100644 index 0000000..a8f0dcc --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/DetailActivity.java @@ -0,0 +1,171 @@ +package mdb.project3.mdbevents; + +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +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.MutableData; +import com.google.firebase.database.Transaction; +import com.google.firebase.database.ValueEventListener; +import com.google.firebase.storage.FirebaseStorage; + +import android.support.v7.graphics.Palette; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; +import android.widget.ToggleButton; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Locale; + + +public class DetailActivity extends AppCompatActivity implements View.OnClickListener { + ScrollView detailScrollView; + FirebaseUser mUser; + String dbKey; + + TextView socialTitleView; + TextView dateTextView; + ImageView eventImageView; + TextView descriptionTextView; + Button interestedButton; + ToggleButton interestedToggleButton; + + DatabaseReference dbRef; + FirebaseStorage mStorage; + FirebaseAuth mAuth; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_detail); + bindViews(); + + dbKey = getIntent().getExtras().getString("DBKEY"); + + Toast.makeText(getApplicationContext(), "Loading event info...", Toast.LENGTH_SHORT).show(); + + dbRef = FirebaseDatabase.getInstance().getReference(); + mStorage = FirebaseStorage.getInstance(); + mAuth = FirebaseAuth.getInstance(); + mUser = mAuth.getCurrentUser(); + + dbRef = dbRef.child("Events").child(dbKey); + dbRef.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot snapshot) { + final Event event = snapshot.getValue(Event.class); + socialTitleView.setText(event.getName()); + dateTextView.setText(event.date); + AsyncTask getBitmap = createDownloadTask(event.imageUrl); + getBitmap.execute(); + descriptionTextView.setText(event.description); + interestedButton.setText(String.format(Locale.getDefault(), "%d people interested", event.numInterested)); + } + + @Override + public void onCancelled(DatabaseError firebaseError) { + + } + }); + + } + + public void bindViews() { + socialTitleView = (TextView) findViewById(R.id.socialTitleView); + dateTextView = (TextView) findViewById(R.id.dateTextView); + eventImageView = (ImageView) findViewById(R.id.eventImageView); + descriptionTextView = (TextView) findViewById(R.id.descriptionTextView); + interestedButton = (Button) findViewById(R.id.InterestedButton); + interestedToggleButton = (ToggleButton) findViewById(R.id.interestedToggleButton); + detailScrollView = (ScrollView) findViewById(R.id.detail_scrollview); + + interestedButton.setOnClickListener(this); + interestedToggleButton.setOnClickListener(this); + } + + private AsyncTask createDownloadTask(final String imageUrl) { + return new AsyncTask() { + @Override + protected Bitmap doInBackground(Void... params) { + try { + URL url = new URL(imageUrl); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoInput(true); + connection.connect(); + InputStream input = connection.getInputStream(); + return BitmapFactory.decodeStream(input); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (bitmap != null) { + eventImageView.setImageBitmap(bitmap); + Palette.from(bitmap).generate(new Palette.PaletteAsyncListener() { + @Override + public void onGenerated(Palette palette) { + interestedButton.setBackgroundColor(palette.getLightVibrantColor(0xFF3396DC)); + interestedToggleButton.setBackgroundColor(palette.getLightMutedColor(0xFF3396DC)); + } + }); + } + super.onPostExecute(bitmap); + } + }; + } + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.interestedToggleButton: + dbRef.runTransaction(new Transaction.Handler() { + @Override + public Transaction.Result doTransaction(MutableData mutableData) { + Event e = mutableData.getValue(Event.class); + if (e == null) + return Transaction.success(mutableData); + if (e.peopleInterested.contains(mUser.getEmail())) { + e.numInterested -= 1; + e.peopleInterested.remove(mUser.getEmail()); + } else { + e.numInterested += 1; + e.peopleInterested.add(mUser.getEmail()); + } + mutableData.setValue(e); + return Transaction.success(mutableData); + } + + @Override + public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) { + + } + }); + break; + case R.id.InterestedButton: + Intent myIntent = new Intent(DetailActivity.this, InterestedActivity.class); + myIntent.putExtra("DBKEY", dbKey); + startActivity(myIntent); + break; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/mdb/project3/mdbevents/Event.java b/app/src/main/java/mdb/project3/mdbevents/Event.java new file mode 100644 index 0000000..3b3d24e --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/Event.java @@ -0,0 +1,63 @@ +package mdb.project3.mdbevents; + +import com.google.firebase.database.IgnoreExtraProperties; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.ResourceBundle; + +/** + * Created by Kedar on 10/4/2016. + */ + +@IgnoreExtraProperties +public class Event implements Comparable{ + + public String name; + public String emailAddress; + public int numInterested; + public String imageUrl; + public String timestamp; + public String date; + public String description; + public List peopleInterested = new ArrayList<>(); + + public Event() { + // Default constructor required for calls to DataSnapshot.getValue(User.class) + } + + public Event(String aName, String aEmailAddress, int aNumInterested, String aImageUrl, String aTimestamp, String aDescription, String aDate, List aPeopleInterested){ + name = aName; + emailAddress = aEmailAddress; + numInterested = aNumInterested; + imageUrl = aImageUrl; + timestamp = aTimestamp; + date = aDate; + peopleInterested = aPeopleInterested; + description = aDescription; + } + public String getName(){ + return name; + } + + public String getEmailAddress(){ + return emailAddress; + } + + public int getNumInterested(){ + return numInterested; + } + + public String getImageUrl(){ + return imageUrl; + } + + public String getTimestamp(){ + return timestamp; + } + + public int compareTo(Event other){ + return other.timestamp.compareTo(timestamp); + } +} diff --git a/app/src/main/java/mdb/project3/mdbevents/EventAdapter.java b/app/src/main/java/mdb/project3/mdbevents/EventAdapter.java new file mode 100644 index 0000000..4629622 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/EventAdapter.java @@ -0,0 +1,89 @@ +package mdb.project3.mdbevents; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.bumptech.glide.Glide; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * Created by Kedar on 10/4/2016. + */ + +public class EventAdapter extends RecyclerView.Adapter { + + private Context context; + public ArrayList eventList; + + public EventAdapter(Context context, ArrayList events) { + this.context = context; + eventList = events; + } + + @Override + public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_view, parent, false); + return new CustomViewHolder(view); + } + + @Override + public void onBindViewHolder(final CustomViewHolder holder, int position) { + Event currEvent = eventList.get(position); + + // Set holders for TextViews to values of the current Event + holder.eventName.setText(currEvent.getName()); + holder.eventEmail.setText(currEvent.getEmailAddress()); + holder.eventInterested.setText(String.format(Locale.getDefault(), "%d are interested", currEvent.getNumInterested())); + + Glide.with(context).load(currEvent.imageUrl).into(holder.eventImage); + } + + @Override + public int getItemCount() { + return eventList.size(); + } + + class CustomViewHolder extends RecyclerView.ViewHolder { + + // Create views to be held by the ViewHolder + ImageView eventImage; + TextView eventName; + TextView eventEmail; + TextView eventInterested; + + public CustomViewHolder(View view) { + super(view); + + // Set the views within the holder to the corresponding XML attributes + this.eventImage = (ImageView) (view.findViewById(R.id.social_image)); + this.eventName = (TextView) (view.findViewById(R.id.event_name)); + this.eventEmail = (TextView) (view.findViewById(R.id.event_email)); + this.eventInterested = (TextView) (view.findViewById(R.id.event_interested)); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(v.getContext(), DetailActivity.class); + intent.putExtra("DBKEY", FeedActivity.databaseKeys.get(getAdapterPosition())); + v.getContext().startActivity(intent); + } + }); + } + } +} + diff --git a/app/src/main/java/mdb/project3/mdbevents/FeedActivity.java b/app/src/main/java/mdb/project3/mdbevents/FeedActivity.java new file mode 100644 index 0000000..80a47a2 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/FeedActivity.java @@ -0,0 +1,128 @@ +package mdb.project3.mdbevents; + +import android.content.Intent; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewConfiguration; +import android.widget.Toast; + +import com.google.firebase.auth.FirebaseAuth; +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.ValueEventListener; + +import java.io.StringBufferInputStream; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class FeedActivity extends AppCompatActivity implements View.OnClickListener { + + EventAdapter eventAdapter; + DatabaseReference rootNode; + + FloatingActionButton createSocialFab; + + static List databaseKeys; + + Toolbar mToolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_feed); + setSupportActionBar((Toolbar) findViewById(R.id.feed_toolbar)); + + // Create a variable for the recycler view and set its layout manager to be linear + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + + // Create a list of test events and bind the event adapter to this list + final ArrayList eventList = new ArrayList<>(); + eventAdapter = new EventAdapter(getApplicationContext(), eventList); + + Toast.makeText(getApplicationContext(), "Loading events...", Toast.LENGTH_SHORT).show(); + + rootNode = FirebaseDatabase.getInstance().getReference(); + DatabaseReference eventNode = rootNode.child("Events"); + eventNode.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot snapshot) { + Log.e("Count ", "" + snapshot.getChildrenCount()); + Map eventToKey = new HashMap<>(); + for (DataSnapshot postSnapshot : snapshot.getChildren()) { + Event event = postSnapshot.getValue(Event.class); + eventToKey.put(event, postSnapshot.getKey()); + eventList.add(event); + } + + Collections.sort(eventList); + + databaseKeys = new ArrayList<>(); + for (Event e : eventList) + databaseKeys.add(eventToKey.get(e)); + + eventAdapter.eventList = eventList; + eventAdapter.notifyDataSetChanged(); + } + + @Override + public void onCancelled(DatabaseError firebaseError) { + Log.e("The read failed: ", firebaseError.getMessage()); + } + }); + + // Set the adapter of the recycler view to the event adapter + recyclerView.setAdapter(eventAdapter); + createSocialFab = (FloatingActionButton) findViewById(R.id.create_social_fab); + createSocialFab.setOnClickListener(this); + } + + public void startNewSocialActivity() { + Intent intent = new Intent(getApplicationContext(), CreateSocial.class); + startActivity(intent); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + switch (id) { + case R.id.create_social_fab: + startNewSocialActivity(); + break; + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.activity_feed, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.sign_out: + FirebaseAuth.getInstance().signOut(); + Intent intent = new Intent(getApplicationContext(), MainActivity.class); + startActivity(intent); + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/mdb/project3/mdbevents/InterestedActivity.java b/app/src/main/java/mdb/project3/mdbevents/InterestedActivity.java new file mode 100644 index 0000000..d40fe1f --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/InterestedActivity.java @@ -0,0 +1,59 @@ +package mdb.project3.mdbevents; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.widget.Toast; + +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.ValueEventListener; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class InterestedActivity extends AppCompatActivity { + + InterestedAdapter interestedAdapter; + DatabaseReference dbRef; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_interested); + + RecyclerView recyclerView = (RecyclerView) (findViewById(R.id.interested_recycler_view)); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + + final List interested = new ArrayList<>(); + + String eventId = getIntent().getStringExtra("DBKEY"); + + dbRef = FirebaseDatabase.getInstance().getReference(); + dbRef = dbRef.child("Events").child(eventId); + interestedAdapter = new InterestedAdapter(getApplicationContext(), interested); + + dbRef.addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot snapshot) { + Log.e("Count " ,""+snapshot.getChildrenCount()); + Event event = snapshot.getValue(Event.class); + + interestedAdapter.interestedList = event.peopleInterested; + interestedAdapter.notifyDataSetChanged(); + } + @Override + public void onCancelled(DatabaseError firebaseError) { + Log.e("The read failed: " ,firebaseError.getMessage()); + } + }); + + + recyclerView.setAdapter(interestedAdapter); + } +} diff --git a/app/src/main/java/mdb/project3/mdbevents/InterestedAdapter.java b/app/src/main/java/mdb/project3/mdbevents/InterestedAdapter.java new file mode 100644 index 0000000..e1ae771 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/InterestedAdapter.java @@ -0,0 +1,51 @@ +package mdb.project3.mdbevents; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by kedarthakkar on 10/13/16. + */ + +public class InterestedAdapter extends RecyclerView.Adapter { + + Context context; + List interestedList; + + public InterestedAdapter (Context context, List list){ + this.context = context; + this.interestedList = list; + } + + public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType){ + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.interested_row, parent, false); + return new InterestedAdapter.CustomViewHolder(view); + } + + public void onBindViewHolder(CustomViewHolder holder, int position){ + String currEmail = interestedList.get(position); + holder.interestedTextView.setText(currEmail); + } + + public int getItemCount(){ + return interestedList.size(); + } + + class CustomViewHolder extends RecyclerView.ViewHolder { + + TextView interestedTextView; + + public CustomViewHolder(View view){ + super(view); + this.interestedTextView = (TextView) (view.findViewById(R.id.interested_email_address)); + } + } + +} diff --git a/app/src/main/java/mdb/project3/mdbevents/MainActivity.java b/app/src/main/java/mdb/project3/mdbevents/MainActivity.java new file mode 100644 index 0000000..260dc93 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/MainActivity.java @@ -0,0 +1,114 @@ +package mdb.project3.mdbevents; + +import android.content.Intent; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.AppCompatButton; +import android.text.TextUtils; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import java.util.HashMap; +import java.util.Map; + +public class MainActivity extends AppCompatActivity implements View.OnClickListener { + + private TextView titleView, emailView, passwordView; + private AppCompatButton signInButton, registerButton; + private FirebaseAuth mAuth; + private FirebaseAuth.AuthStateListener mAuthListener; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + initializeViews(); + mAuth = FirebaseAuth.getInstance(); + + mAuthListener = new FirebaseAuth.AuthStateListener() { + @Override + public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { + FirebaseUser user = firebaseAuth.getCurrentUser(); + if (user != null) { + startActivity(new Intent(MainActivity.this, FeedActivity.class)); + } + } + }; + } + + @Override + protected void onStart() { + super.onStart(); + mAuth.addAuthStateListener(mAuthListener); + } + + @Override + protected void onStop() { + super.onStop(); + if (mAuthListener != null) { + mAuth.removeAuthStateListener(mAuthListener); + } + } + + private void initializeViews() { + titleView = (TextView) findViewById(R.id.title_view); + emailView = (TextView) findViewById(R.id.email_input); + passwordView = (TextView) findViewById(R.id.password_input); + signInButton = (AppCompatButton) findViewById(R.id.login_button); + registerButton = (AppCompatButton) findViewById(R.id.register_button); + + Typeface customFont = Typeface.createFromAsset(getAssets(), "fonts/cornerstone.ttf"); + titleView.setTypeface(customFont); + passwordView.setTypeface(Typeface.DEFAULT); + signInButton.setOnClickListener(this); + registerButton.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.register_button) { + Intent myIntent = new Intent(MainActivity.this, RegisterActivity.class); + myIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(myIntent); + } else if (id == R.id.login_button) { + signIn(emailView.getText().toString(), passwordView.getText().toString()); + } + } + + private void signIn(String email, String password) { + if (!validate(email, password)) + return; + Toast.makeText(getApplicationContext(), "Logging in...", Toast.LENGTH_SHORT).show(); + mAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) + Toast.makeText(getApplicationContext(), R.string.auth_failed, Toast.LENGTH_SHORT).show(); + } + }); + } + + private boolean validate(String email, String password) { + boolean valid = !(TextUtils.isEmpty(email) || + TextUtils.isEmpty(password)); + if (!valid) { + Snackbar.make(findViewById(R.id.activity_register), + "Required fields are empty", + Snackbar.LENGTH_SHORT).show(); + } + return valid; + } +} diff --git a/app/src/main/java/mdb/project3/mdbevents/RegisterActivity.java b/app/src/main/java/mdb/project3/mdbevents/RegisterActivity.java new file mode 100644 index 0000000..bef9b1d --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/RegisterActivity.java @@ -0,0 +1,125 @@ +package mdb.project3.mdbevents; + +import android.content.Intent; +import android.graphics.Typeface; +import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.AppCompatButton; +import android.text.TextUtils; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; +import com.google.firebase.auth.UserProfileChangeRequest; + +public class RegisterActivity extends AppCompatActivity implements View.OnClickListener { + private TextView registerTitle; + private EditText fullNameInput, + registerEmailInput, + registerPasswordInput; + private AppCompatButton signUpButton; + + private FirebaseAuth mAuth; + private FirebaseAuth.AuthStateListener mAuthListener; + private FirebaseUser user; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_register); + + initializeViews(); + + mAuth = FirebaseAuth.getInstance(); + mAuthListener = new FirebaseAuth.AuthStateListener() { + @Override + public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) { + FirebaseUser user = firebaseAuth.getCurrentUser(); + if (user != null) { + // User is signed in + } + } + }; + } + + @Override + protected void onStart() { + super.onStart(); + mAuth.addAuthStateListener(mAuthListener); + } + + @Override + protected void onStop() { + super.onStop(); + if (mAuthListener != null) { + mAuth.removeAuthStateListener(mAuthListener); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.sign_up_button) { + createAccount(fullNameInput.getText().toString(), + registerEmailInput.getText().toString(), + registerPasswordInput.getText().toString()); + } + } + + private void initializeViews() { + registerTitle = (TextView) findViewById(R.id.register_title); + fullNameInput = (EditText) findViewById(R.id.full_name_input); + registerEmailInput = (EditText) findViewById(R.id.register_email_input); + registerPasswordInput = (EditText) findViewById(R.id.register_password_input); + signUpButton = (AppCompatButton) findViewById(R.id.sign_up_button); + + Typeface customFont = Typeface.createFromAsset(getAssets(), "fonts/cornerstone.ttf"); + registerTitle.setTypeface(customFont); + registerPasswordInput.setTypeface(Typeface.DEFAULT); + signUpButton.setOnClickListener(this); + } + + + private void createAccount(final String fullName, String email, String password) { + if (!validate(fullName, email, password)) + return; + mAuth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(this, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + // If registering fails + if (task.isSuccessful()) { + updateUserInfo(fullName); + } else { + Toast.makeText(getApplicationContext(), R.string.auth_failed, Toast.LENGTH_SHORT).show(); + } + } + }); + } + + private boolean validate(String fullName, String email, String password) { + boolean valid = !(TextUtils.isEmpty(fullName) || + TextUtils.isEmpty(email) || + TextUtils.isEmpty(password)); + if (!valid) { + Snackbar.make(findViewById(R.id.activity_register), + "Required fields are empty", + Snackbar.LENGTH_SHORT).show(); + } + return valid; + } + + private void updateUserInfo(String fullName) { + user = mAuth.getCurrentUser(); + UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder() + .setDisplayName(fullName).build(); + user.updateProfile(profileUpdates); + } +} \ No newline at end of file diff --git a/app/src/main/java/mdb/project3/mdbevents/SplashScreen.java b/app/src/main/java/mdb/project3/mdbevents/SplashScreen.java new file mode 100644 index 0000000..2f1e9c9 --- /dev/null +++ b/app/src/main/java/mdb/project3/mdbevents/SplashScreen.java @@ -0,0 +1,28 @@ +package mdb.project3.mdbevents; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.FirebaseUser; + +/** + * Created by emaanhariri on 10/14/16. + */ + +public class SplashScreen extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onCreate(savedInstanceState); + + FirebaseUser mUser = FirebaseAuth.getInstance().getCurrentUser(); + if (mUser == null) + startActivity(new Intent(SplashScreen.this, MainActivity.class)); + else + startActivity(new Intent(SplashScreen.this, FeedActivity.class)); + finish(); + } +} diff --git a/app/src/main/res/drawable/background_splash.xml b/app/src/main/res/drawable/background_splash.xml new file mode 100644 index 0000000..4072f29 --- /dev/null +++ b/app/src/main/res/drawable/background_splash.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml b/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml new file mode 100644 index 0000000..3d2ba42 --- /dev/null +++ b/app/src/main/res/drawable/ic_add_a_photo_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_add_white_24dp.xml b/app/src/main/res/drawable/ic_add_white_24dp.xml new file mode 100644 index 0000000..b9b8eca --- /dev/null +++ b/app/src/main/res/drawable/ic_add_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml b/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml new file mode 100644 index 0000000..c872f16 --- /dev/null +++ b/app/src/main/res/drawable/ic_camera_alt_black_24dp.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_check_circle_black_24dp.xml b/app/src/main/res/drawable/ic_check_circle_black_24dp.xml new file mode 100644 index 0000000..1241eda --- /dev/null +++ b/app/src/main/res/drawable/ic_check_circle_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_drawable.xml b/app/src/main/res/drawable/ic_drawable.xml new file mode 100644 index 0000000..401cbf6 --- /dev/null +++ b/app/src/main/res/drawable/ic_drawable.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_loop_white_24dp.xml b/app/src/main/res/drawable/ic_loop_white_24dp.xml new file mode 100644 index 0000000..905355e --- /dev/null +++ b/app/src/main/res/drawable/ic_loop_white_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/text_cursor_yellow.xml b/app/src/main/res/drawable/text_cursor_yellow.xml new file mode 100644 index 0000000..c0f7ea4 --- /dev/null +++ b/app/src/main/res/drawable/text_cursor_yellow.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_create_social.xml b/app/src/main/res/layout/activity_create_social.xml new file mode 100644 index 0000000..2bba0d6 --- /dev/null +++ b/app/src/main/res/layout/activity_create_social.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml new file mode 100644 index 0000000..a70e22d --- /dev/null +++ b/app/src/main/res/layout/activity_detail.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + +