From 194931948c85ee6bcb0588a5058d5f106fe3137b Mon Sep 17 00:00:00 2001 From: Sam Stern Date: Mon, 10 Sep 2018 14:46:10 -0700 Subject: [PATCH 1/6] Move java files Change-Id: Ifcb9ce439a1c3e383e11f75b3c5e159af1e5c6b8 --- database/app/proguard-rules.pro | 4 ++-- .../google/firebase/quickstart/database/NewPostTest.java | 2 ++ database/app/src/main/AndroidManifest.xml | 8 ++++---- .../quickstart/database/{ => java}/BaseActivity.java | 2 +- .../quickstart/database/{ => java}/MainActivity.java | 9 +++++---- .../quickstart/database/{ => java}/NewPostActivity.java | 7 ++++--- .../database/{ => java}/PostDetailActivity.java | 9 +++++---- .../quickstart/database/{ => java}/SignInActivity.java | 5 +++-- .../database/{ => java}/fragment/MyPostsFragment.java | 2 +- .../database/{ => java}/fragment/MyTopPostsFragment.java | 2 +- .../database/{ => java}/fragment/PostListFragment.java | 8 ++++---- .../{ => java}/fragment/RecentPostsFragment.java | 2 +- .../quickstart/database/{ => java}/models/Comment.java | 2 +- .../quickstart/database/{ => java}/models/Post.java | 2 +- .../quickstart/database/{ => java}/models/User.java | 2 +- .../database/{ => java}/viewholder/PostViewHolder.java | 4 ++-- database/app/src/main/res/layout/activity_main.xml | 3 +-- database/app/src/main/res/layout/activity_new_post.xml | 3 +-- .../app/src/main/res/layout/activity_post_detail.xml | 3 +-- database/app/src/main/res/layout/activity_sign_in.xml | 3 +-- database/app/src/main/res/layout/fragment_all_posts.xml | 3 +-- database/app/src/main/res/menu/menu_main.xml | 3 +-- 22 files changed, 44 insertions(+), 44 deletions(-) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/BaseActivity.java (93%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/MainActivity.java (91%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/NewPostActivity.java (95%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/PostDetailActivity.java (97%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/SignInActivity.java (96%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/fragment/MyPostsFragment.java (86%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/fragment/MyTopPostsFragment.java (90%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/fragment/PostListFragment.java (96%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/fragment/RecentPostsFragment.java (90%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/models/Comment.java (89%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/models/Post.java (94%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/models/User.java (87%) rename database/app/src/main/java/com/google/firebase/quickstart/database/{ => java}/viewholder/PostViewHolder.java (89%) 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..b4d97eed62 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; diff --git a/database/app/src/main/AndroidManifest.xml b/database/app/src/main/AndroidManifest.xml index 31650c4463..55a1c918f8 100644 --- a/database/app/src/main/AndroidManifest.xml +++ b/database/app/src/main/AndroidManifest.xml @@ -9,18 +9,18 @@ android:supportsRtl="true" android:theme="@style/AppTheme"> - - + + - + 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 91% 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..b5ebf79622 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 { 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 95% 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..4fe2c93e31 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; 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 97% 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..5892afbe6d 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; 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 96% 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..129c0bf2d3 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 { 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 96% 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..0796b6b5c1 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 { 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 89% 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..81530cb6f7 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 { diff --git a/database/app/src/main/res/layout/activity_main.xml b/database/app/src/main/res/layout/activity_main.xml index d3fb82495c..99cbceac69 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"> + android:paddingTop="@dimen/activity_vertical_margin"> + android:layout_height="match_parent"> + xmlns:tools="http://schemas.android.com/tools"> Date: Mon, 10 Sep 2018 15:45:08 -0700 Subject: [PATCH 2/6] Convert all Java to Kotlin Change-Id: I0f9de2781911366c29045fa1a312e97e019d5632 --- database/app/build.gradle | 11 + .../quickstart/database/NewPostTest.java | 32 +-- .../database/java/MainActivity.java | 2 +- .../database/java/NewPostActivity.java | 6 +- .../database/java/PostDetailActivity.java | 14 +- .../database/java/SignInActivity.java | 12 +- .../java/viewholder/PostViewHolder.java | 8 +- .../database/kotlin/BaseActivity.kt | 35 +++ .../database/kotlin/MainActivity.kt | 84 ++++++ .../database/kotlin/NewPostActivity.kt | 120 ++++++++ .../database/kotlin/PostDetailActivity.kt | 269 ++++++++++++++++++ .../database/kotlin/SignInActivity.kt | 149 ++++++++++ .../kotlin/fragment/MyPostsFragment.kt | 16 ++ .../kotlin/fragment/MyTopPostsFragment.kt | 19 ++ .../kotlin/fragment/PostListFragment.kt | 161 +++++++++++ .../kotlin/fragment/RecentPostsFragment.kt | 19 ++ .../database/kotlin/models/Comment.kt | 11 + .../quickstart/database/kotlin/models/Post.kt | 32 +++ .../quickstart/database/kotlin/models/User.kt | 9 + .../kotlin/viewholder/PostViewHolder.kt | 30 ++ .../app/src/main/res/layout/activity_main.xml | 2 +- .../src/main/res/layout/activity_new_post.xml | 8 +- .../main/res/layout/activity_post_detail.xml | 18 +- .../src/main/res/layout/activity_sign_in.xml | 14 +- .../main/res/layout/include_post_author.xml | 4 +- .../src/main/res/layout/include_post_text.xml | 4 +- .../app/src/main/res/layout/item_post.xml | 12 +- 27 files changed, 1033 insertions(+), 68 deletions(-) create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseActivity.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainActivity.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailActivity.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Comment.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Post.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/User.kt create mode 100644 database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/PostViewHolder.kt diff --git a/database/app/build.gradle b/database/app/build.gradle index 8018c3482f..6df8b41d3c 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,14 @@ configurations.all { resolutionStrategy.force 'com.android.support:support-annotations:27.1.1' } +androidExtensions { + experimental = true +} + dependencies { + implementation project(':internal') + 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/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java b/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java index b4d97eed62..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 @@ -48,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" @@ -101,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/java/com/google/firebase/quickstart/database/java/MainActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java index b5ebf79622..b738a6ad30 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainActivity.java @@ -76,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/java/NewPostActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java index 4fe2c93e31..ad11b716e0 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java @@ -42,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/java/PostDetailActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java index 5892afbe6d..aed2a402bd 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java @@ -64,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)); @@ -131,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(); } } diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java index 129c0bf2d3..3b81edfe0a 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java @@ -41,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); @@ -164,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/java/viewholder/PostViewHolder.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java index 81530cb6f7..f3e1609ad6 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/PostViewHolder.java @@ -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..bafd0e8e0a --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainActivity.kt @@ -0,0 +1,84 @@ +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.support.v4.view.ViewPager +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 + private lateinit var viewPager: ViewPager + + 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(): Int { + return fragments.size + } + + override fun getPageTitle(position: Int): CharSequence? { + return fragmentNames[position] + } + } + + // Set up the ViewPager with the sections adapter. + container.adapter = pagerAdapter + tabs.setupWithViewPager(viewPager) + + // Button launches NewPostActivity + fabNewPost.setOnClickListener { + startActivity(Intent(this@MainActivity, 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..0b2fa448e7 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt @@ -0,0 +1,120 @@ +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(this@NewPostActivity, + "Error: could not fetch user.", + Toast.LENGTH_SHORT).show() + } else { + // Write new post + writeNewPost(userId, user.username!!, 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 + if (enabled) { + fabSubmitPost.visibility = View.VISIBLE + } else { + fabSubmitPost.visibility = 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 + 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) + } + + companion object { + + private const val TAG = "NewPostActivity" + private const val REQUIRED = "Required" + + } + // [END write_fan_out] +} 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..86a0d19999 --- /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.TextView +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 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] + postAuthor.text = post!!.author + postTitle.text = post.title + postBody.text = post.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(this@PostDetailActivity, "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) + 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) { + + var authorView: TextView + var bodyView: TextView + + init { + authorView = itemView.findViewById(R.id.comment_author) + bodyView = itemView.findViewById(R.id.comment_body) + } + } + + 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) { + // 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) { + val comment = comments[position] + holder.authorView.text = comment.author + holder.bodyView.text = comment.text + } + + override fun getItemCount(): Int { + return comments.size + } + + fun cleanupListener() { + if (childEventListener != null) { + databaseReference.removeEventListener(childEventListener) + } + } + + } + + 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..c3bdfd3c3d --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt @@ -0,0 +1,149 @@ +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(this@SignInActivity, "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(this@SignInActivity, "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 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..9f6941094a --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.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 +import com.google.firebase.quickstart.database.java.fragment.PostListFragment + + +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..c481d8ecc6 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt @@ -0,0 +1,19 @@ +package com.google.firebase.quickstart.database.kotlin.fragment + +import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.Query +import com.google.firebase.quickstart.database.java.fragment.PostListFragment + + +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..457418c4d8 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt @@ -0,0 +1,161 @@ +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 + + +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] + + recycler = rootView.findViewById(R.id.messages_list) + recycler.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, object : View.OnClickListener { + + override fun onClick(v: View?) { + // 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() + if (adapter != null) { + adapter!!.startListening() + } + } + + override fun onStop() { + super.onStop() + if (adapter != null) { + 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..ea6b4f8a13 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt @@ -0,0 +1,19 @@ +package com.google.firebase.quickstart.database.kotlin.fragment + +import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.Query +import com.google.firebase.quickstart.database.java.fragment.PostListFragment + + +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 + // [END recent_posts_query] + + return databaseReference.child("posts") + .limitToFirst(100) + } +} 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 99cbceac69..d754ce179a 100644 --- a/database/app/src/main/res/layout/activity_main.xml +++ b/database/app/src/main/res/layout/activity_main.xml @@ -16,7 +16,7 @@ android:layout_below="@+id/tabs" />