diff --git a/database/app/build.gradle b/database/app/build.gradle
index 8018c3482f..778f1cfc2e 100644
--- a/database/app/build.gradle
+++ b/database/app/build.gradle
@@ -1,4 +1,8 @@
apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'org.jetbrains.kotlin.android.extensions'
+
check.dependsOn 'assembleDebugAndroidTest'
android {
@@ -26,7 +30,15 @@ configurations.all {
resolutionStrategy.force 'com.android.support:support-annotations:27.1.1'
}
+androidExtensions {
+ experimental = true
+}
+
dependencies {
+ implementation project(":internal:lintchecks")
+ implementation project(":internal:chooser")
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.61"
+
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:recyclerview-v7:27.1.1'
implementation 'com.android.support:cardview-v7:27.1.1'
diff --git a/database/app/proguard-rules.pro b/database/app/proguard-rules.pro
index ca062aa993..8ff48d15fb 100644
--- a/database/app/proguard-rules.pro
+++ b/database/app/proguard-rules.pro
@@ -21,10 +21,10 @@
-keepattributes EnclosingMethod
-keepattributes InnerClasses
--keep class com.google.firebase.quickstart.database.viewholder.** {
+-keep class com.google.firebase.quickstart.database.java.viewholder.** {
*;
}
--keepclassmembers class com.google.firebase.quickstart.database.models.** {
+-keepclassmembers class com.google.firebase.quickstart.database.java.models.** {
*;
}
diff --git a/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java b/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java
index 4a25c0a916..a183b04054 100644
--- a/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java
+++ b/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java
@@ -8,6 +8,8 @@
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
+import com.google.firebase.quickstart.database.java.SignInActivity;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -46,50 +48,50 @@ public void newPostTest() {
// Select email field
ViewInteraction appCompatEditText = onView(
- allOf(withId(R.id.field_email),
- withParent(withId(R.id.layout_email_password)),
+ allOf(withId(R.id.fieldEmail),
+ withParent(withId(R.id.layoutEmailPassword)),
isDisplayed()));
appCompatEditText.perform(click());
// Enter email address
ViewInteraction appCompatEditText2 = onView(
- allOf(withId(R.id.field_email),
- withParent(withId(R.id.layout_email_password)),
+ allOf(withId(R.id.fieldEmail),
+ withParent(withId(R.id.layoutEmailPassword)),
isDisplayed()));
appCompatEditText2.perform(replaceText(email));
// Enter password
ViewInteraction appCompatEditText3 = onView(
- allOf(withId(R.id.field_password),
- withParent(withId(R.id.layout_email_password)),
+ allOf(withId(R.id.fieldPassword),
+ withParent(withId(R.id.layoutEmailPassword)),
isDisplayed()));
appCompatEditText3.perform(replaceText(password));
// Click sign up
ViewInteraction appCompatButton = onView(
- allOf(withId(R.id.button_sign_up), withText(R.string.sign_up),
- withParent(withId(R.id.layout_buttons)),
+ allOf(withId(R.id.buttonSignUp), withText(R.string.sign_up),
+ withParent(withId(R.id.layoutButtons)),
isDisplayed()));
appCompatButton.perform(click());
// Click new post button
ViewInteraction floatingActionButton = onView(
- allOf(withId(R.id.fab_new_post), isDisplayed()));
+ allOf(withId(R.id.fabNewPost), isDisplayed()));
floatingActionButton.perform(click());
// Enter post title
ViewInteraction appCompatEditText4 = onView(
- allOf(withId(R.id.field_title), isDisplayed()));
+ allOf(withId(R.id.fieldTitle), isDisplayed()));
appCompatEditText4.perform(replaceText(postTitle));
// Enter post content
ViewInteraction appCompatEditText5 = onView(
- allOf(withId(R.id.field_body), isDisplayed()));
+ allOf(withId(R.id.fieldBody), isDisplayed()));
appCompatEditText5.perform(replaceText(postContent));
// Click submit button
ViewInteraction floatingActionButton2 = onView(
- allOf(withId(R.id.fab_submit_post), isDisplayed()));
+ allOf(withId(R.id.fabSubmitPost), isDisplayed()));
floatingActionButton2.perform(click());
// Navigate to "My Posts"
@@ -99,18 +101,18 @@ public void newPostTest() {
// Check that the title is correct
ViewInteraction textView = onView(
- allOf(withId(R.id.post_title), withText(postTitle), isDisplayed()));
+ allOf(withId(R.id.postTitle), withText(postTitle), isDisplayed()));
textView.check(matches(withText(postTitle)));
// Check that the content is correct
ViewInteraction textView2 = onView(
- allOf(withId(R.id.post_body), withText(postContent), isDisplayed()));
+ allOf(withId(R.id.postBody), withText(postContent), isDisplayed()));
textView2.check(matches(withText(postContent)));
// Check that it has zero stars
ViewInteraction textView3 = onView(
- allOf(withId(R.id.post_num_stars), withText("0"),
- withParent(withId(R.id.star_layout)),
+ allOf(withId(R.id.postNumStars), withText("0"),
+ withParent(withId(R.id.starLayout)),
isDisplayed()));
textView3.check(matches(withText("0")));
diff --git a/database/app/src/main/AndroidManifest.xml b/database/app/src/main/AndroidManifest.xml
index 31650c4463..9e54173bb2 100644
--- a/database/app/src/main/AndroidManifest.xml
+++ b/database/app/src/main/AndroidManifest.xml
@@ -8,19 +8,33 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/EntryChoiceActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/EntryChoiceActivity.kt
new file mode 100644
index 0000000000..ca165d47f0
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/EntryChoiceActivity.kt
@@ -0,0 +1,22 @@
+package com.google.firebase.quickstart.database
+
+import android.content.Intent
+import com.firebase.example.internal.BaseEntryChoiceActivity
+import com.firebase.example.internal.Choice
+
+class EntryChoiceActivity : BaseEntryChoiceActivity() {
+
+ override fun getChoices(): List {
+ return listOf(
+ Choice(
+ "Java",
+ "Run the Firebase Realtime Database quickstart written in Java.",
+ Intent(this, com.google.firebase.quickstart.database.java.MainActivity::class.java)),
+ Choice(
+ "Kotlin",
+ "Run the Firebase Realtime Database quickstart written in Kotlin.",
+ Intent(this, com.google.firebase.quickstart.database.kotlin.MainActivity::class.java))
+ )
+ }
+
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/BaseActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java
similarity index 93%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/BaseActivity.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java
index 481246eddd..c2e7306da9 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/BaseActivity.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database;
+package com.google.firebase.quickstart.database.java;
import android.app.ProgressDialog;
import android.support.v7.app.AppCompatActivity;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/MainActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java
similarity index 88%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/MainActivity.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java
index bc11df00a2..b738a6ad30 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/MainActivity.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.google.firebase.quickstart.database;
+package com.google.firebase.quickstart.database.java;
import android.content.Intent;
import android.os.Bundle;
@@ -27,9 +27,10 @@
import android.view.View;
import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.quickstart.database.fragment.MyPostsFragment;
-import com.google.firebase.quickstart.database.fragment.MyTopPostsFragment;
-import com.google.firebase.quickstart.database.fragment.RecentPostsFragment;
+import com.google.firebase.quickstart.database.R;
+import com.google.firebase.quickstart.database.java.fragment.MyPostsFragment;
+import com.google.firebase.quickstart.database.java.fragment.MyTopPostsFragment;
+import com.google.firebase.quickstart.database.java.fragment.RecentPostsFragment;
public class MainActivity extends BaseActivity {
@@ -75,7 +76,7 @@ public CharSequence getPageTitle(int position) {
tabLayout.setupWithViewPager(mViewPager);
// Button launches NewPostActivity
- findViewById(R.id.fab_new_post).setOnClickListener(new View.OnClickListener() {
+ findViewById(R.id.fabNewPost).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startActivity(new Intent(MainActivity.this, NewPostActivity.class));
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/NewPostActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java
similarity index 92%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/NewPostActivity.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java
index a2a378deae..ad11b716e0 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/NewPostActivity.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database;
+package com.google.firebase.quickstart.database.java;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
@@ -13,8 +13,9 @@
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
-import com.google.firebase.quickstart.database.models.Post;
-import com.google.firebase.quickstart.database.models.User;
+import com.google.firebase.quickstart.database.R;
+import com.google.firebase.quickstart.database.java.models.Post;
+import com.google.firebase.quickstart.database.java.models.User;
import java.util.HashMap;
import java.util.Map;
@@ -41,9 +42,9 @@ protected void onCreate(Bundle savedInstanceState) {
mDatabase = FirebaseDatabase.getInstance().getReference();
// [END initialize_database_ref]
- mTitleField = findViewById(R.id.field_title);
- mBodyField = findViewById(R.id.field_body);
- mSubmitButton = findViewById(R.id.fab_submit_post);
+ mTitleField = findViewById(R.id.fieldTitle);
+ mBodyField = findViewById(R.id.fieldBody);
+ mSubmitButton = findViewById(R.id.fabSubmitPost);
mSubmitButton.setOnClickListener(new View.OnClickListener() {
@Override
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/PostDetailActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java
similarity index 93%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/PostDetailActivity.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java
index 3818e5c43b..d375348c59 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/PostDetailActivity.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database;
+package com.google.firebase.quickstart.database.java;
import android.content.Context;
import android.os.Bundle;
@@ -19,9 +19,10 @@
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
-import com.google.firebase.quickstart.database.models.User;
-import com.google.firebase.quickstart.database.models.Comment;
-import com.google.firebase.quickstart.database.models.Post;
+import com.google.firebase.quickstart.database.R;
+import com.google.firebase.quickstart.database.java.models.User;
+import com.google.firebase.quickstart.database.java.models.Comment;
+import com.google.firebase.quickstart.database.java.models.Post;
import java.util.ArrayList;
import java.util.List;
@@ -63,12 +64,12 @@ protected void onCreate(Bundle savedInstanceState) {
.child("post-comments").child(mPostKey);
// Initialize Views
- mAuthorView = findViewById(R.id.post_author);
- mTitleView = findViewById(R.id.post_title);
- mBodyView = findViewById(R.id.post_body);
- mCommentField = findViewById(R.id.field_comment_text);
- mCommentButton = findViewById(R.id.button_post_comment);
- mCommentsRecycler = findViewById(R.id.recycler_comments);
+ mAuthorView = findViewById(R.id.postAuthor);
+ mTitleView = findViewById(R.id.postTitle);
+ mBodyView = findViewById(R.id.postBody);
+ mCommentField = findViewById(R.id.fieldCommentText);
+ mCommentButton = findViewById(R.id.buttonPostComment);
+ mCommentsRecycler = findViewById(R.id.recyclerPostComments);
mCommentButton.setOnClickListener(this);
mCommentsRecycler.setLayoutManager(new LinearLayoutManager(this));
@@ -130,7 +131,7 @@ public void onStop() {
@Override
public void onClick(View v) {
int i = v.getId();
- if (i == R.id.button_post_comment) {
+ if (i == R.id.buttonPostComment) {
postComment();
}
}
@@ -171,8 +172,8 @@ private static class CommentViewHolder extends RecyclerView.ViewHolder {
public CommentViewHolder(View itemView) {
super(itemView);
- authorView = itemView.findViewById(R.id.comment_author);
- bodyView = itemView.findViewById(R.id.comment_body);
+ authorView = itemView.findViewById(R.id.commentAuthor);
+ bodyView = itemView.findViewById(R.id.commentBody);
}
}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/SignInActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java
similarity index 91%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/SignInActivity.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java
index 5aa24cac1f..3b81edfe0a 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/SignInActivity.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database;
+package com.google.firebase.quickstart.database.java;
import android.content.Intent;
import android.os.Bundle;
@@ -17,7 +17,8 @@
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
-import com.google.firebase.quickstart.database.models.User;
+import com.google.firebase.quickstart.database.R;
+import com.google.firebase.quickstart.database.java.models.User;
public class SignInActivity extends BaseActivity implements View.OnClickListener {
@@ -40,10 +41,10 @@ protected void onCreate(Bundle savedInstanceState) {
mAuth = FirebaseAuth.getInstance();
// Views
- mEmailField = findViewById(R.id.field_email);
- mPasswordField = findViewById(R.id.field_password);
- mSignInButton = findViewById(R.id.button_sign_in);
- mSignUpButton = findViewById(R.id.button_sign_up);
+ mEmailField = findViewById(R.id.fieldEmail);
+ mPasswordField = findViewById(R.id.fieldPassword);
+ mSignInButton = findViewById(R.id.buttonSignIn);
+ mSignUpButton = findViewById(R.id.buttonSignUp);
// Click listeners
mSignInButton.setOnClickListener(this);
@@ -163,9 +164,9 @@ private void writeNewUser(String userId, String name, String email) {
@Override
public void onClick(View v) {
int i = v.getId();
- if (i == R.id.button_sign_in) {
+ if (i == R.id.buttonSignIn) {
signIn();
- } else if (i == R.id.button_sign_up) {
+ } else if (i == R.id.buttonSignUp) {
signUp();
}
}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java
similarity index 86%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyPostsFragment.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java
index 79e08561ba..fbec06163a 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyPostsFragment.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.fragment;
+package com.google.firebase.quickstart.database.java.fragment;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.Query;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyTopPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyTopPostsFragment.java
similarity index 90%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyTopPostsFragment.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyTopPostsFragment.java
index ed197abade..8600d1d32e 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/MyTopPostsFragment.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyTopPostsFragment.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.fragment;
+package com.google.firebase.quickstart.database.java.fragment;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.Query;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/PostListFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java
similarity index 95%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/fragment/PostListFragment.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java
index f2ec666cc7..bde0fc09be 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/PostListFragment.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.fragment;
+package com.google.firebase.quickstart.database.java.fragment;
import android.content.Intent;
import android.os.Bundle;
@@ -20,10 +20,10 @@
import com.google.firebase.database.MutableData;
import com.google.firebase.database.Query;
import com.google.firebase.database.Transaction;
-import com.google.firebase.quickstart.database.PostDetailActivity;
+import com.google.firebase.quickstart.database.java.PostDetailActivity;
import com.google.firebase.quickstart.database.R;
-import com.google.firebase.quickstart.database.models.Post;
-import com.google.firebase.quickstart.database.viewholder.PostViewHolder;
+import com.google.firebase.quickstart.database.java.models.Post;
+import com.google.firebase.quickstart.database.java.viewholder.PostViewHolder;
public abstract class PostListFragment extends Fragment {
@@ -49,7 +49,7 @@ public View onCreateView (LayoutInflater inflater, ViewGroup container,
mDatabase = FirebaseDatabase.getInstance().getReference();
// [END create_database_reference]
- mRecycler = rootView.findViewById(R.id.messages_list);
+ mRecycler = rootView.findViewById(R.id.messagesList);
mRecycler.setHasFixedSize(true);
return rootView;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/RecentPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java
similarity index 90%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/fragment/RecentPostsFragment.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java
index 8038d5713f..48c936d307 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/fragment/RecentPostsFragment.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.fragment;
+package com.google.firebase.quickstart.database.java.fragment;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.Query;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/models/Comment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java
similarity index 89%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/models/Comment.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java
index 7e734941ae..f670f3900c 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/models/Comment.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.models;
+package com.google.firebase.quickstart.database.java.models;
import com.google.firebase.database.IgnoreExtraProperties;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/models/Post.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java
similarity index 94%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/models/Post.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java
index 71dbea00f7..0c42d38fd3 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/models/Post.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.models;
+package com.google.firebase.quickstart.database.java.models;
import com.google.firebase.database.Exclude;
import com.google.firebase.database.IgnoreExtraProperties;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/models/User.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java
similarity index 87%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/models/User.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java
index 595b7099a4..d8c241dce4 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/models/User.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.models;
+package com.google.firebase.quickstart.database.java.models;
import com.google.firebase.database.IgnoreExtraProperties;
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/viewholder/PostViewHolder.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java
similarity index 69%
rename from database/app/src/main/java/com/google/firebase/quickstart/database/viewholder/PostViewHolder.java
rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java
index fbf26abac0..f3e1609ad6 100644
--- a/database/app/src/main/java/com/google/firebase/quickstart/database/viewholder/PostViewHolder.java
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java
@@ -1,4 +1,4 @@
-package com.google.firebase.quickstart.database.viewholder;
+package com.google.firebase.quickstart.database.java.viewholder;
import android.support.v7.widget.RecyclerView;
import android.view.View;
@@ -6,7 +6,7 @@
import android.widget.TextView;
import com.google.firebase.quickstart.database.R;
-import com.google.firebase.quickstart.database.models.Post;
+import com.google.firebase.quickstart.database.java.models.Post;
public class PostViewHolder extends RecyclerView.ViewHolder {
@@ -19,11 +19,11 @@ public class PostViewHolder extends RecyclerView.ViewHolder {
public PostViewHolder(View itemView) {
super(itemView);
- titleView = itemView.findViewById(R.id.post_title);
- authorView = itemView.findViewById(R.id.post_author);
+ titleView = itemView.findViewById(R.id.postTitle);
+ authorView = itemView.findViewById(R.id.postAuthor);
starView = itemView.findViewById(R.id.star);
- numStarsView = itemView.findViewById(R.id.post_num_stars);
- bodyView = itemView.findViewById(R.id.post_body);
+ numStarsView = itemView.findViewById(R.id.postNumStars);
+ bodyView = itemView.findViewById(R.id.postBody);
}
public void bindToPost(Post post, View.OnClickListener starClickListener) {
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseActivity.kt
new file mode 100644
index 0000000000..5668de7575
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseActivity.kt
@@ -0,0 +1,35 @@
+package com.google.firebase.quickstart.database.kotlin
+
+import android.app.ProgressDialog
+import android.support.v7.app.AppCompatActivity
+import com.google.firebase.auth.FirebaseAuth
+
+open class BaseActivity : AppCompatActivity() {
+
+ private var progressDialog: ProgressDialog? = null
+
+ val uid: String
+ get() = FirebaseAuth.getInstance().currentUser!!.uid
+
+ fun showProgressDialog() {
+ if (progressDialog == null) {
+ val pd = ProgressDialog(this)
+ pd.setCancelable(false)
+ pd.setMessage("Loading...")
+
+ progressDialog = pd
+ }
+
+ progressDialog?.show()
+ }
+
+ fun hideProgressDialog() {
+ progressDialog?.let {
+ if (it.isShowing) {
+ it.dismiss()
+ }
+ }
+ }
+
+
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainActivity.kt
new file mode 100644
index 0000000000..f9505d87e1
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainActivity.kt
@@ -0,0 +1,80 @@
+package com.google.firebase.quickstart.database.kotlin
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentPagerAdapter
+import android.view.Menu
+import android.view.MenuItem
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.fragment.MyPostsFragment
+import com.google.firebase.quickstart.database.kotlin.fragment.MyTopPostsFragment
+import com.google.firebase.quickstart.database.kotlin.fragment.RecentPostsFragment
+import kotlinx.android.synthetic.main.activity_main.*
+
+class MainActivity : BaseActivity() {
+
+ private lateinit var pagerAdapter: FragmentPagerAdapter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ // Create the adapter that will return a fragment for each section
+ pagerAdapter = object : FragmentPagerAdapter(supportFragmentManager) {
+ private val fragments = arrayOf(
+ RecentPostsFragment(),
+ MyPostsFragment(),
+ MyTopPostsFragment())
+
+ private val fragmentNames = arrayOf(
+ getString(R.string.heading_recent),
+ getString(R.string.heading_my_posts),
+ getString(R.string.heading_my_top_posts))
+
+ override fun getItem(position: Int): Fragment {
+ return fragments[position]
+ }
+
+ override fun getCount() = fragments.size
+
+ override fun getPageTitle(position: Int): CharSequence? {
+ return fragmentNames[position]
+ }
+ }
+
+ // Set up the ViewPager with the sections adapter.
+ container.adapter = pagerAdapter
+ tabs.setupWithViewPager(container)
+
+ // Button launches NewPostActivity
+ fabNewPost.setOnClickListener {
+ startActivity(Intent(this, NewPostActivity::class.java))
+ }
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_main, menu)
+ return true
+ }
+
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ val i = item.itemId
+ if (i == R.id.action_logout) {
+ FirebaseAuth.getInstance().signOut()
+ startActivity(Intent(this, SignInActivity::class.java))
+ finish()
+ return true
+ } else {
+ return super.onOptionsItemSelected(item)
+ }
+ }
+
+ companion object {
+
+ private const val TAG = "MainActivity"
+
+ }
+
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt
new file mode 100644
index 0000000000..720151a56f
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt
@@ -0,0 +1,125 @@
+package com.google.firebase.quickstart.database.kotlin
+
+import android.os.Bundle
+import android.text.TextUtils
+import android.util.Log
+import android.view.View
+import android.widget.Toast
+import com.google.firebase.database.*
+import com.google.firebase.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.models.Post
+import com.google.firebase.quickstart.database.kotlin.models.User
+import kotlinx.android.synthetic.main.activity_new_post.*
+import java.util.*
+
+class NewPostActivity : BaseActivity() {
+
+ // [START declare_database_ref]
+ private lateinit var database: DatabaseReference
+ // [END declare_database_ref]
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_new_post)
+
+ // [START initialize_database_ref]
+ database = FirebaseDatabase.getInstance().reference
+ // [END initialize_database_ref]
+
+ fabSubmitPost.setOnClickListener { submitPost() }
+ }
+
+ private fun submitPost() {
+ val title = fieldTitle.text.toString()
+ val body = fieldBody.text.toString()
+
+ // Title is required
+ if (TextUtils.isEmpty(title)) {
+ fieldTitle.error = REQUIRED
+ return
+ }
+
+ // Body is required
+ if (TextUtils.isEmpty(body)) {
+ fieldBody.error = REQUIRED
+ return
+ }
+
+ // Disable button so there are no multi-posts
+ setEditingEnabled(false)
+ Toast.makeText(this, "Posting...", Toast.LENGTH_SHORT).show()
+
+ // [START single_value_read]
+ val userId = uid
+ database.child("users").child(userId).addListenerForSingleValueEvent(
+ object : ValueEventListener {
+ override fun onDataChange(dataSnapshot: DataSnapshot) {
+ // Get user value
+ val user = dataSnapshot.getValue(User::class.java)
+
+ // [START_EXCLUDE]
+ if (user == null) {
+ // User is null, error out
+ Log.e(TAG, "User $userId is unexpectedly null")
+ Toast.makeText(baseContext,
+ "Error: could not fetch user.",
+ Toast.LENGTH_SHORT).show()
+ } else {
+ // Write new post
+ writeNewPost(userId, user.username.toString(), title, body)
+ }
+
+ // Finish this Activity, back to the stream
+ setEditingEnabled(true)
+ finish()
+ // [END_EXCLUDE]
+ }
+
+ override fun onCancelled(databaseError: DatabaseError) {
+ Log.w(TAG, "getUser:onCancelled", databaseError.toException())
+ // [START_EXCLUDE]
+ setEditingEnabled(true)
+ // [END_EXCLUDE]
+ }
+ })
+ // [END single_value_read]
+ }
+
+ private fun setEditingEnabled(enabled: Boolean) {
+ fieldTitle.isEnabled = enabled
+ fieldBody.isEnabled = enabled
+ fabSubmitPost.visibility = if (enabled) {
+ View.VISIBLE
+ } else {
+ View.GONE
+ }
+ }
+
+ // [START write_fan_out]
+ private fun writeNewPost(userId: String, username: String, title: String, body: String) {
+ // Create new post at /user-posts/$userid/$postid and at
+ // /posts/$postid simultaneously
+ val key = database.child("posts").push().key
+ if (key == null) {
+ Log.w(TAG, "Couldn't get push key for posts")
+ return
+ }
+
+ val post = Post(userId, username, title, body)
+ val postValues = post.toMap()
+
+ val childUpdates = HashMap()
+ childUpdates["/posts/$key"] = postValues
+ childUpdates["/user-posts/$userId/$key"] = postValues
+
+ database.updateChildren(childUpdates)
+ }
+ // [END write_fan_out]
+
+ companion object {
+
+ private const val TAG = "NewPostActivity"
+ private const val REQUIRED = "Required"
+
+ }
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailActivity.kt
new file mode 100644
index 0000000000..ba3962ab86
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailActivity.kt
@@ -0,0 +1,269 @@
+package com.google.firebase.quickstart.database.kotlin
+
+import android.content.Context
+import android.os.Bundle
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import com.google.firebase.database.*
+import com.google.firebase.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.models.Comment
+import com.google.firebase.quickstart.database.kotlin.models.Post
+import com.google.firebase.quickstart.database.kotlin.models.User
+import kotlinx.android.synthetic.main.activity_post_detail.*
+import kotlinx.android.synthetic.main.include_post_author.*
+import kotlinx.android.synthetic.main.include_post_text.*
+import kotlinx.android.synthetic.main.item_comment.view.*
+import java.util.*
+
+class PostDetailActivity : BaseActivity(), View.OnClickListener {
+
+ private lateinit var postKey: String
+ private lateinit var postReference: DatabaseReference
+ private lateinit var commentsReference: DatabaseReference
+
+ private var postListener: ValueEventListener? = null
+ private var adapter: CommentAdapter? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_post_detail)
+
+ // Get post key from intent
+ postKey = intent.getStringExtra(EXTRA_POST_KEY) ?:
+ throw IllegalArgumentException("Must pass EXTRA_POST_KEY")
+
+ // Initialize Database
+ postReference = FirebaseDatabase.getInstance().reference
+ .child("posts").child(postKey)
+ commentsReference = FirebaseDatabase.getInstance().reference
+ .child("post-comments").child(postKey)
+
+ // Initialize Views
+ buttonPostComment.setOnClickListener(this)
+ recyclerPostComments.layoutManager = LinearLayoutManager(this)
+
+ }
+
+ public override fun onStart() {
+ super.onStart()
+
+ // Add value event listener to the post
+ // [START post_value_event_listener]
+ val postListener = object : ValueEventListener {
+ override fun onDataChange(dataSnapshot: DataSnapshot) {
+ // Get Post object and use the values to update the UI
+ val post = dataSnapshot.getValue(Post::class.java)
+ // [START_EXCLUDE]
+ post?.let {
+ postAuthor.text = it.author
+ postTitle.text = it.title
+ postBody.text = it.body
+ }
+ // [END_EXCLUDE]
+ }
+
+ override fun onCancelled(databaseError: DatabaseError) {
+ // Getting Post failed, log a message
+ Log.w(TAG, "loadPost:onCancelled", databaseError.toException())
+ // [START_EXCLUDE]
+ Toast.makeText(baseContext, "Failed to load post.",
+ Toast.LENGTH_SHORT).show()
+ // [END_EXCLUDE]
+ }
+ }
+ postReference.addValueEventListener(postListener)
+ // [END post_value_event_listener]
+
+ // Keep copy of post listener so we can remove it when app stops
+ this.postListener = postListener
+
+ // Listen for comments
+ adapter = CommentAdapter(this, commentsReference)
+ recyclerPostComments.adapter = adapter
+ }
+
+ public override fun onStop() {
+ super.onStop()
+
+ // Remove post value event listener
+ postListener?.let {
+ postReference.removeEventListener(it)
+ }
+
+ // Clean up comments listener
+ adapter?.cleanupListener()
+ }
+
+ override fun onClick(v: View) {
+ val i = v.id
+ if (i == R.id.buttonPostComment) {
+ postComment()
+ }
+ }
+
+ private fun postComment() {
+ val uid = uid
+ FirebaseDatabase.getInstance().reference.child("users").child(uid)
+ .addListenerForSingleValueEvent(object : ValueEventListener {
+ override fun onDataChange(dataSnapshot: DataSnapshot) {
+ // Get user information
+ val user = dataSnapshot.getValue(User::class.java)
+ if (user == null) {
+ return
+ }
+
+ val authorName = user.username
+
+ // Create new comment object
+ val commentText = fieldCommentText.text.toString()
+ val comment = Comment(uid, authorName, commentText)
+
+ // Push the comment, it will appear in the list
+ commentsReference.push().setValue(comment)
+
+ // Clear the field
+ fieldCommentText.text = null
+ }
+
+ override fun onCancelled(databaseError: DatabaseError) {
+
+ }
+ })
+ }
+
+ private class CommentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bind(comment: Comment) {
+ itemView.commentAuthor.text = comment.author
+ itemView.commentBody.text = comment.text
+ }
+
+ }
+
+ private class CommentAdapter(private val context: Context,
+ private val databaseReference: DatabaseReference) : RecyclerView.Adapter() {
+
+ private val childEventListener: ChildEventListener?
+
+ private val commentIds = ArrayList()
+ private val comments = ArrayList()
+
+ init {
+
+ // Create child event listener
+ // [START child_event_listener_recycler]
+ val childEventListener = object : ChildEventListener {
+ override fun onChildAdded(dataSnapshot: DataSnapshot, previousChildName: String?) {
+ Log.d(TAG, "onChildAdded:" + dataSnapshot.key!!)
+
+ // A new comment has been added, add it to the displayed list
+ val comment = dataSnapshot.getValue(Comment::class.java)
+
+ // [START_EXCLUDE]
+ // Update RecyclerView
+ commentIds.add(dataSnapshot.key!!)
+ comments.add(comment!!)
+ notifyItemInserted(comments.size - 1)
+ // [END_EXCLUDE]
+ }
+
+ override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) {
+ Log.d(TAG, "onChildChanged: ${dataSnapshot.key}")
+
+ // A comment has changed, use the key to determine if we are displaying this
+ // comment and if so displayed the changed comment.
+ val newComment = dataSnapshot.getValue(Comment::class.java)
+ val commentKey = dataSnapshot.key
+
+ // [START_EXCLUDE]
+ val commentIndex = commentIds.indexOf(commentKey)
+ if (commentIndex > -1 && newComment != null) {
+ // Replace with the new data
+ comments.set(commentIndex, newComment)
+
+ // Update the RecyclerView
+ notifyItemChanged(commentIndex)
+ } else {
+ Log.w(TAG, "onChildChanged:unknown_child: $commentKey")
+ }
+ // [END_EXCLUDE]
+ }
+
+ override fun onChildRemoved(dataSnapshot: DataSnapshot) {
+ Log.d(TAG, "onChildRemoved:" + dataSnapshot.key!!)
+
+ // A comment has changed, use the key to determine if we are displaying this
+ // comment and if so remove it.
+ val commentKey = dataSnapshot.key
+
+ // [START_EXCLUDE]
+ val commentIndex = commentIds.indexOf(commentKey)
+ if (commentIndex > -1) {
+ // Remove data from the list
+ commentIds.removeAt(commentIndex)
+ comments.removeAt(commentIndex)
+
+ // Update the RecyclerView
+ notifyItemRemoved(commentIndex)
+ } else {
+ Log.w(TAG, "onChildRemoved:unknown_child:" + commentKey!!)
+ }
+ // [END_EXCLUDE]
+ }
+
+ override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) {
+ Log.d(TAG, "onChildMoved:" + dataSnapshot.key!!)
+
+ // A comment has changed position, use the key to determine if we are
+ // displaying this comment and if so move it.
+ val movedComment = dataSnapshot.getValue(Comment::class.java)
+ val commentKey = dataSnapshot.key
+
+ // ...
+ }
+
+ override fun onCancelled(databaseError: DatabaseError) {
+ Log.w(TAG, "postComments:onCancelled", databaseError.toException())
+ Toast.makeText(context, "Failed to load comments.",
+ Toast.LENGTH_SHORT).show()
+ }
+ }
+ databaseReference.addChildEventListener(childEventListener)
+ // [END child_event_listener_recycler]
+
+ // Store reference to listener so it can be removed on app stop
+ this.childEventListener = childEventListener
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommentViewHolder {
+ val inflater = LayoutInflater.from(context)
+ val view = inflater.inflate(R.layout.item_comment, parent, false)
+ return CommentViewHolder(view)
+ }
+
+ override fun onBindViewHolder(holder: CommentViewHolder, position: Int) {
+ holder.bind(comments[position])
+ }
+
+ override fun getItemCount(): Int = comments.size
+
+ fun cleanupListener() {
+ childEventListener?.let {
+ databaseReference.removeEventListener(it)
+ }
+ }
+
+ }
+
+ companion object {
+
+ private const val TAG = "PostDetailActivity"
+ const val EXTRA_POST_KEY = "post_key"
+
+ }
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt
new file mode 100644
index 0000000000..0480a9fc2a
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt
@@ -0,0 +1,150 @@
+package com.google.firebase.quickstart.database.kotlin
+
+import android.content.Intent
+import android.os.Bundle
+import android.text.TextUtils
+import android.util.Log
+import android.view.View
+import android.widget.Toast
+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.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.models.User
+import kotlinx.android.synthetic.main.activity_sign_in.*
+
+class SignInActivity : BaseActivity(), View.OnClickListener {
+
+ private lateinit var database: DatabaseReference
+ private lateinit var auth: FirebaseAuth
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_sign_in)
+
+ database = FirebaseDatabase.getInstance().reference
+ auth = FirebaseAuth.getInstance()
+
+ // Click listeners
+ buttonSignIn.setOnClickListener(this)
+ buttonSignUp.setOnClickListener(this)
+ }
+
+ public override fun onStart() {
+ super.onStart()
+
+ // Check auth on Activity start
+ auth.currentUser?.let {
+ onAuthSuccess(it)
+ }
+ }
+
+ private fun signIn() {
+ Log.d(TAG, "signIn")
+ if (!validateForm()) {
+ return
+ }
+
+ showProgressDialog()
+ val email = fieldEmail.text.toString()
+ val password = fieldPassword.text.toString()
+
+ auth.signInWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ Log.d(TAG, "signIn:onComplete:" + task.isSuccessful)
+ hideProgressDialog()
+
+ if (task.isSuccessful) {
+ onAuthSuccess(task.result.user)
+ } else {
+ Toast.makeText(baseContext, "Sign In Failed",
+ Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ private fun signUp() {
+ Log.d(TAG, "signUp")
+ if (!validateForm()) {
+ return
+ }
+
+ showProgressDialog()
+ val email = fieldEmail.text.toString()
+ val password = fieldPassword.text.toString()
+
+ auth.createUserWithEmailAndPassword(email, password)
+ .addOnCompleteListener(this) { task ->
+ Log.d(TAG, "createUser:onComplete:" + task.isSuccessful)
+ hideProgressDialog()
+
+ if (task.isSuccessful) {
+ onAuthSuccess(task.result.user)
+ } else {
+ Toast.makeText(baseContext, "Sign Up Failed",
+ Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ private fun onAuthSuccess(user: FirebaseUser) {
+ val username = usernameFromEmail(user.email!!)
+
+ // Write new user
+ writeNewUser(user.uid, username, user.email)
+
+ // Go to MainActivity
+ startActivity(Intent(this@SignInActivity, MainActivity::class.java))
+ finish()
+ }
+
+ private fun usernameFromEmail(email: String): String {
+ return if (email.contains("@")) {
+ email.split("@".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0]
+ } else {
+ email
+ }
+ }
+
+ private fun validateForm(): Boolean {
+ var result = true
+ if (TextUtils.isEmpty(fieldEmail.text.toString())) {
+ fieldEmail.error = "Required"
+ result = false
+ } else {
+ fieldEmail.error = null
+ }
+
+ if (TextUtils.isEmpty(fieldPassword.text.toString())) {
+ fieldPassword.error = "Required"
+ result = false
+ } else {
+ fieldPassword.error = null
+ }
+
+ return result
+ }
+
+ // [START basic_write]
+ private fun writeNewUser(userId: String, name: String, email: String?) {
+ val user = User(name, email)
+ database.child("users").child(userId).setValue(user)
+ }
+ // [END basic_write]
+
+ override fun onClick(v: View) {
+ val i = v.id
+ if (i == R.id.buttonSignIn) {
+ signIn()
+ } else if (i == R.id.buttonSignUp) {
+ signUp()
+ }
+ }
+
+ companion object {
+
+ private const val TAG = "SignInActivity"
+
+ }
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.kt
new file mode 100644
index 0000000000..ba2ab82500
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.kt
@@ -0,0 +1,15 @@
+package com.google.firebase.quickstart.database.kotlin.fragment
+
+import com.google.firebase.database.DatabaseReference
+import com.google.firebase.database.Query
+
+
+class MyPostsFragment : PostListFragment() {
+
+ override fun getQuery(databaseReference: DatabaseReference): Query {
+ // All my posts
+ return databaseReference.child("user-posts")
+ .child(uid)
+ }
+
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt
new file mode 100644
index 0000000000..b72523115d
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt
@@ -0,0 +1,18 @@
+package com.google.firebase.quickstart.database.kotlin.fragment
+
+import com.google.firebase.database.DatabaseReference
+import com.google.firebase.database.Query
+
+
+class MyTopPostsFragment : PostListFragment() {
+
+ override fun getQuery(databaseReference: DatabaseReference): Query {
+ // [START my_top_posts_query]
+ // My top posts by number of stars
+ val myUserId = uid
+ // [END my_top_posts_query]
+
+ return databaseReference.child("user-posts").child(myUserId)
+ .orderByChild("starCount")
+ }
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt
new file mode 100644
index 0000000000..5fc2e33c51
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt
@@ -0,0 +1,153 @@
+package com.google.firebase.quickstart.database.kotlin.fragment
+
+import android.content.Intent
+import android.os.Bundle
+import android.support.v4.app.Fragment
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.firebase.ui.database.FirebaseRecyclerAdapter
+import com.firebase.ui.database.FirebaseRecyclerOptions
+import com.google.firebase.auth.FirebaseAuth
+import com.google.firebase.database.*
+import com.google.firebase.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.PostDetailActivity
+import com.google.firebase.quickstart.database.kotlin.models.Post
+import com.google.firebase.quickstart.database.kotlin.viewholder.PostViewHolder
+import kotlinx.android.synthetic.main.fragment_all_posts.view.*
+
+
+abstract class PostListFragment : Fragment() {
+
+ // [START define_database_reference]
+ private lateinit var database: DatabaseReference
+ // [END define_database_reference]
+
+ private lateinit var recycler: RecyclerView
+ private lateinit var manager: LinearLayoutManager
+ private var adapter: FirebaseRecyclerAdapter? = null
+
+ val uid: String
+ get() = FirebaseAuth.getInstance().currentUser!!.uid
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?): View? {
+ super.onCreateView(inflater, container, savedInstanceState)
+ val rootView = inflater.inflate(R.layout.fragment_all_posts, container, false)
+
+ // [START create_database_reference]
+ database = FirebaseDatabase.getInstance().reference
+ // [END create_database_reference]
+
+ rootView.messagesList.setHasFixedSize(true)
+
+ return rootView
+ }
+
+ override fun onActivityCreated(savedInstanceState: Bundle?) {
+ super.onActivityCreated(savedInstanceState)
+
+ // Set up Layout Manager, reverse layout
+ manager = LinearLayoutManager(activity)
+ manager.reverseLayout = true
+ manager.stackFromEnd = true
+ recycler.layoutManager = manager
+
+ // Set up FirebaseRecyclerAdapter with the Query
+ val postsQuery = getQuery(database)
+
+ val options = FirebaseRecyclerOptions.Builder()
+ .setQuery(postsQuery, Post::class.java)
+ .build()
+
+ adapter = object : FirebaseRecyclerAdapter(options) {
+
+ override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): PostViewHolder {
+ val inflater = LayoutInflater.from(viewGroup.context)
+ return PostViewHolder(inflater.inflate(R.layout.item_post, viewGroup, false))
+ }
+
+ override fun onBindViewHolder(viewHolder: PostViewHolder, position: Int, model: Post) {
+ val postRef = getRef(position)
+
+ // Set click listener for the whole post view
+ val postKey = postRef.key
+ viewHolder.itemView.setOnClickListener {
+ // Launch PostDetailActivity
+ val intent = Intent(activity, PostDetailActivity::class.java)
+ intent.putExtra(PostDetailActivity.EXTRA_POST_KEY, postKey)
+ startActivity(intent)
+ }
+
+ // Determine if the current user has liked this post and set UI accordingly
+ viewHolder.setLikedState(model.stars.containsKey(uid))
+
+ // Bind Post to ViewHolder, setting OnClickListener for the star button
+ viewHolder.bindToPost(model, View.OnClickListener {
+ // Need to write to both places the post is stored
+ val globalPostRef = database.child("posts").child(postRef.key!!)
+ val userPostRef = database.child("user-posts").child(model.uid!!).child(postRef.key!!)
+
+ // Run two transactions
+ onStarClicked(globalPostRef)
+ onStarClicked(userPostRef)
+ })
+ }
+ }
+ recycler.adapter = adapter
+ }
+
+ // [START post_stars_transaction]
+ private fun onStarClicked(postRef: DatabaseReference) {
+ postRef.runTransaction(object : Transaction.Handler {
+ override fun doTransaction(mutableData: MutableData): Transaction.Result {
+ val p = mutableData.getValue(Post::class.java)
+ ?: return Transaction.success(mutableData)
+
+ if (p.stars.containsKey(uid)) {
+ // Unstar the post and remove self from stars
+ p.starCount = p.starCount - 1
+ p.stars.remove(uid)
+ } else {
+ // Star the post and add self to stars
+ p.starCount = p.starCount + 1
+ p.stars[uid] = true
+ }
+
+ // Set value and report transaction success
+ mutableData.value = p
+ return Transaction.success(mutableData)
+ }
+
+ override fun onComplete(databaseError: DatabaseError?, b: Boolean,
+ dataSnapshot: DataSnapshot?) {
+ // Transaction completed
+ Log.d(TAG, "postTransaction:onComplete:" + databaseError!!)
+ }
+ })
+ }
+ // [END post_stars_transaction]
+
+
+ override fun onStart() {
+ super.onStart()
+ adapter?.startListening()
+ }
+
+ override fun onStop() {
+ super.onStop()
+ adapter?.stopListening()
+ }
+
+ abstract fun getQuery(databaseReference: DatabaseReference): Query
+
+ companion object {
+
+ private const val TAG = "PostListFragment"
+
+ }
+
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt
new file mode 100644
index 0000000000..b48382f1e2
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt
@@ -0,0 +1,16 @@
+package com.google.firebase.quickstart.database.kotlin.fragment
+
+import com.google.firebase.database.DatabaseReference
+import com.google.firebase.database.Query
+
+class RecentPostsFragment : PostListFragment() {
+
+ override fun getQuery(databaseReference: DatabaseReference): Query {
+ // [START recent_posts_query]
+ // Last 100 posts, these are automatically the 100 most recent
+ // due to sorting by push() keys.
+ return databaseReference.child("posts")
+ .limitToFirst(100)
+ // [END recent_posts_query]
+ }
+}
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Comment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Comment.kt
new file mode 100644
index 0000000000..92bf04dbdc
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Comment.kt
@@ -0,0 +1,11 @@
+package com.google.firebase.quickstart.database.kotlin.models
+
+import com.google.firebase.database.IgnoreExtraProperties
+
+// [START comment_class]
+@IgnoreExtraProperties
+data class Comment(
+ var uid: String? = "",
+ var author: String? = "",
+ var text: String? = "")
+// [END comment_class]
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Post.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Post.kt
new file mode 100644
index 0000000000..fcd83b9461
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Post.kt
@@ -0,0 +1,32 @@
+package com.google.firebase.quickstart.database.kotlin.models
+
+import com.google.firebase.database.Exclude
+import com.google.firebase.database.IgnoreExtraProperties
+import java.util.*
+
+// [START post_class]
+@IgnoreExtraProperties
+data class Post(
+ var uid: String? = "",
+ var author: String? = "",
+ var title: String? = "",
+ var body: String? = "",
+ var starCount: Int = 0,
+ var stars: MutableMap = HashMap()) {
+
+ // [START post_to_map]
+ @Exclude
+ fun toMap(): Map {
+ return mapOf(
+ "uid" to uid,
+ "author" to author,
+ "title" to title,
+ "body" to body,
+ "starCount" to starCount,
+ "stars" to stars
+ )
+ }
+ // [END post_to_map]
+
+}
+// [END post_class]
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/User.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/User.kt
new file mode 100644
index 0000000000..3b055dd64d
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/User.kt
@@ -0,0 +1,9 @@
+package com.google.firebase.quickstart.database.kotlin.models
+
+import com.google.firebase.database.IgnoreExtraProperties
+
+// [START blog_user_class]
+@IgnoreExtraProperties
+data class User(var username: String? = "",
+ var email: String? = "")
+// [END blog_user_class]
diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/PostViewHolder.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/PostViewHolder.kt
new file mode 100644
index 0000000000..eb6bc6e105
--- /dev/null
+++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/PostViewHolder.kt
@@ -0,0 +1,30 @@
+package com.google.firebase.quickstart.database.kotlin.viewholder
+
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import com.google.firebase.quickstart.database.R
+import com.google.firebase.quickstart.database.kotlin.models.Post
+import kotlinx.android.synthetic.main.include_post_author.view.*
+import kotlinx.android.synthetic.main.include_post_text.view.*
+import kotlinx.android.synthetic.main.item_post.view.*
+
+class PostViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+
+ fun bindToPost(post: Post, starClickListener: View.OnClickListener) {
+ itemView.postTitle.text = post.title
+ itemView.postAuthor.text = post.author
+ itemView.postNumStars.text = post.starCount.toString()
+ itemView.postBody.text = post.body
+
+ itemView.star.setOnClickListener(starClickListener)
+ }
+
+ fun setLikedState(liked: Boolean) {
+ if (liked) {
+ itemView.star.setImageResource(R.drawable.ic_toggle_star_24)
+ } else {
+ itemView.star.setImageResource(R.drawable.ic_toggle_star_outline_24)
+ }
+ }
+
+}
diff --git a/database/app/src/main/res/layout/activity_main.xml b/database/app/src/main/res/layout/activity_main.xml
index d3fb82495c..d754ce179a 100644
--- a/database/app/src/main/res/layout/activity_main.xml
+++ b/database/app/src/main/res/layout/activity_main.xml
@@ -2,8 +2,7 @@
+ android:layout_height="match_parent">
+ android:layout_height="match_parent">
+ android:paddingTop="@dimen/activity_vertical_margin">
diff --git a/database/app/src/main/res/layout/activity_sign_in.xml b/database/app/src/main/res/layout/activity_sign_in.xml
index c224a98a22..4001c30451 100644
--- a/database/app/src/main/res/layout/activity_sign_in.xml
+++ b/database/app/src/main/res/layout/activity_sign_in.xml
@@ -6,8 +6,7 @@
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.quickstart.database.SignInActivity">
+ android:paddingTop="@dimen/activity_vertical_margin">
diff --git a/database/app/src/main/res/layout/fragment_all_posts.xml b/database/app/src/main/res/layout/fragment_all_posts.xml
index e43a56ecf7..6ec1f2ced1 100644
--- a/database/app/src/main/res/layout/fragment_all_posts.xml
+++ b/database/app/src/main/res/layout/fragment_all_posts.xml
@@ -2,11 +2,10 @@
+ android:layout_height="match_parent">
+ android:layout_toRightOf="@+id/commentPhoto">
@@ -37,7 +37,7 @@
android:src="@drawable/ic_toggle_star_outline_24" />
diff --git a/database/app/src/main/res/menu/menu_main.xml b/database/app/src/main/res/menu/menu_main.xml
index c37e899829..2b7d6bf680 100644
--- a/database/app/src/main/res/menu/menu_main.xml
+++ b/database/app/src/main/res/menu/menu_main.xml
@@ -1,7 +1,6 @@