diff --git a/database/app/build.gradle b/database/app/build.gradle index 48da37374..a2484c6da 100644 --- a/database/app/build.gradle +++ b/database/app/build.gradle @@ -35,6 +35,8 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.navigation:navigation-fragment-ktx:2.3.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.3.2' // Import the Firebase BoM (see: https://firebase.google.com/docs/android/learn-more#bom) implementation platform('com.google.firebase:firebase-bom:26.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 deleted file mode 100644 index 8913c54a1..000000000 --- a/database/app/src/androidTest/java/com/google/firebase/quickstart/database/NewPostTest.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.google.firebase.quickstart.database; - - -import androidx.test.InstrumentationRegistry; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.ViewInteraction; -import androidx.test.rule.ActivityTestRule; -import androidx.test.runner.AndroidJUnit4; -import androidx.test.filters.LargeTest; - -import com.google.firebase.quickstart.database.java.SignInActivity; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Random; - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.replaceText; -import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static androidx.test.espresso.matcher.ViewMatchers.withParent; -import static androidx.test.espresso.matcher.ViewMatchers.withText; -import static org.hamcrest.CoreMatchers.allOf; - -@LargeTest -@RunWith(AndroidJUnit4.class) -public class NewPostTest { - - @Rule - public ActivityTestRule mActivityTestRule = new ActivityTestRule<>(SignInActivity.class); - - @Test - public void newPostTest() { - // Generate user and post content - String username = "user" + randomDigits(); - String email = username + "@example.com"; - String password = "testuser"; - String postTitle = "Title " + randomDigits(); - String postContent = "Content " + randomDigits(); - - // Go back to the sign in screen if we're logged in from a previous test - logOutIfPossible(); - - // Select email field - ViewInteraction appCompatEditText = onView( - allOf(withId(R.id.fieldEmail), isDisplayed())); - appCompatEditText.perform(click()); - - // Enter email address - ViewInteraction appCompatEditText2 = onView( - allOf(withId(R.id.fieldEmail), isDisplayed())); - appCompatEditText2.perform(replaceText(email)); - - // Enter password - ViewInteraction appCompatEditText3 = onView( - allOf(withId(R.id.fieldPassword), isDisplayed())); - appCompatEditText3.perform(replaceText(password)); - - // Click sign up - ViewInteraction appCompatButton = onView( - allOf(withId(R.id.buttonSignUp), withText(R.string.sign_up), isDisplayed())); - appCompatButton.perform(click()); - - // Click new post button - ViewInteraction floatingActionButton = onView( - allOf(withId(R.id.fabNewPost), isDisplayed())); - floatingActionButton.perform(click()); - - // Enter post title - ViewInteraction appCompatEditText4 = onView( - allOf(withId(R.id.fieldTitle), isDisplayed())); - appCompatEditText4.perform(replaceText(postTitle)); - - // Enter post content - ViewInteraction appCompatEditText5 = onView( - allOf(withId(R.id.fieldBody), isDisplayed())); - appCompatEditText5.perform(replaceText(postContent)); - - // Click submit button - ViewInteraction floatingActionButton2 = onView( - allOf(withId(R.id.fabSubmitPost), isDisplayed())); - floatingActionButton2.perform(click()); - - // Navigate to "My Posts" - ViewInteraction appCompatTextView = onView( - allOf(withText(R.string.heading_my_posts), isDisplayed())); - appCompatTextView.perform(click()); - - // Check that the title is correct - ViewInteraction textView = onView( - 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.postBody), withText(postContent), isDisplayed())); - textView2.check(matches(withText(postContent))); - - // Check that it has zero stars - ViewInteraction textView3 = onView( - allOf(withId(R.id.postNumStars), withText("0"), isDisplayed())); - textView3.check(matches(withText("0"))); - - } - - /** - * Click the 'Log Out' overflow menu if it exists (which would mean we're signed in). - */ - private void logOutIfPossible() { - try { - openActionBarOverflowOrOptionsMenu(InstrumentationRegistry.getTargetContext()); - onView(withText(R.string.menu_logout)).perform(click()); - } catch (NoMatchingViewException e) { - // Ignore exception since we only want to do this operation if it's easy. - } - - } - - /** - * Generate a random string of digits. - */ - private String randomDigits() { - Random random = new Random(); - return String.valueOf(random.nextInt(99999999)); - } - -} diff --git a/database/app/src/main/AndroidManifest.xml b/database/app/src/main/AndroidManifest.xml index 9e54173bb..dbc576a8f 100644 --- a/database/app/src/main/AndroidManifest.xml +++ b/database/app/src/main/AndroidManifest.xml @@ -20,21 +20,12 @@ + android:theme="@style/AppTheme.NoActionBar" /> - - - - - - - - - + android:theme="@style/AppTheme.NoActionBar" /> 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 index 0ebb2112b..da957ffaf 100644 --- 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 @@ -11,11 +11,11 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() { Choice( "Java", "Run the Firebase Realtime Database quickstart written in Java.", - Intent(this, com.google.firebase.quickstart.database.java.SignInActivity::class.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.SignInActivity::class.java)) + Intent(this, com.google.firebase.quickstart.database.kotlin.MainActivity::class.java)) ) } } diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseFragment.java similarity index 81% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseFragment.java index 49f5d78cb..f6b0d4d0e 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseActivity.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/BaseFragment.java @@ -3,17 +3,15 @@ import android.view.View; import android.widget.ProgressBar; -import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; import com.google.firebase.auth.FirebaseAuth; - -public class BaseActivity extends AppCompatActivity { - +public class BaseFragment extends Fragment { private ProgressBar mProgressBar; public void setProgressBar(int resId) { - mProgressBar = findViewById(resId); + mProgressBar = getView().findViewById(resId); } public void showProgressBar() { @@ -31,6 +29,4 @@ public void hideProgressBar() { public String getUid() { return FirebaseAuth.getInstance().getCurrentUser().getUid(); } - - } 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 b47828701..a0cea2b65 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 @@ -16,91 +16,51 @@ package com.google.firebase.quickstart.database.java; -import android.content.Intent; import android.os.Bundle; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentPagerAdapter; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; +import androidx.navigation.NavController; +import androidx.navigation.NavDestination; +import androidx.navigation.Navigation; -import com.google.firebase.auth.FirebaseAuth; +import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.firebase.quickstart.database.R; import com.google.firebase.quickstart.database.databinding.ActivityMainBinding; -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 { +public class MainActivity extends AppCompatActivity { - private static final String TAG = "MainActivity"; + private FloatingActionButton fab; + private NavController navController; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); + setSupportActionBar(binding.toolbar); - // Create the adapter that will return a fragment for each section - FragmentPagerAdapter mPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager(), - FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - private final Fragment[] mFragments = new Fragment[]{ - new RecentPostsFragment(), - new MyPostsFragment(), - new MyTopPostsFragment(), - }; - private final String[] mFragmentNames = new String[]{ - getString(R.string.heading_recent), - getString(R.string.heading_my_posts), - getString(R.string.heading_my_top_posts) - }; + fab = binding.fab; + navController = Navigation.findNavController(this, R.id.nav_host_fragment); + navController.setGraph(R.navigation.nav_graph_java); + navController.addOnDestinationChangedListener(new NavController.OnDestinationChangedListener() { @Override - public Fragment getItem(int position) { - return mFragments[position]; - } - - @Override - public int getCount() { - return mFragments.length; - } - - @Override - public CharSequence getPageTitle(int position) { - return mFragmentNames[position]; - } - }; - // Set up the ViewPager with the sections adapter. - binding.container.setAdapter(mPagerAdapter); - binding.tabs.setupWithViewPager(binding.container); - - // Button launches NewPostActivity - binding.fabNewPost.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startActivity(new Intent(MainActivity.this, NewPostActivity.class)); + public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) { + if (destination.getId() == R.id.MainFragment) { + fab.setVisibility(View.VISIBLE); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + navController.navigate(R.id.action_MainFragment_to_NewPostFragment); + } + }); + } else { + fab.setVisibility(View.GONE); + } } }); } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int i = item.getItemId(); - if (i == R.id.action_logout) { - FirebaseAuth.getInstance().signOut(); - startActivity(new Intent(this, SignInActivity.class)); - finish(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - } diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainFragment.java new file mode 100644 index 000000000..3195e26bc --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/MainFragment.java @@ -0,0 +1,91 @@ +package com.google.firebase.quickstart.database.java; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentPagerAdapter; +import androidx.navigation.fragment.NavHostFragment; + +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.quickstart.database.R; +import com.google.firebase.quickstart.database.databinding.FragmentMainBinding; +import com.google.firebase.quickstart.database.java.listfragments.MyPostsFragment; +import com.google.firebase.quickstart.database.java.listfragments.MyTopPostsFragment; +import com.google.firebase.quickstart.database.java.listfragments.RecentPostsFragment; + +public class MainFragment extends Fragment { + + private FragmentMainBinding binding; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentMainBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setHasOptionsMenu(true); + + // Create the adapter that will return a fragment for each section + FragmentPagerAdapter mPagerAdapter = new FragmentPagerAdapter(getParentFragmentManager(), + FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + private final Fragment[] mFragments = new Fragment[]{ + new RecentPostsFragment(), + new MyPostsFragment(), + new MyTopPostsFragment(), + }; + private final String[] mFragmentNames = new String[]{ + getString(R.string.heading_recent), + getString(R.string.heading_my_posts), + getString(R.string.heading_my_top_posts) + }; + + @Override + public Fragment getItem(int position) { + return mFragments[position]; + } + + @Override + public int getCount() { + return mFragments.length; + } + + @Override + public CharSequence getPageTitle(int position) { + return mFragmentNames[position]; + } + }; + // Set up the ViewPager with the sections adapter. + binding.container.setAdapter(mPagerAdapter); + binding.tabs.setupWithViewPager(binding.container); + } + + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + inflater.inflate(R.menu.menu_main, menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int i = item.getItemId(); + if (i == R.id.action_logout) { + FirebaseAuth.getInstance().signOut(); + NavHostFragment.findNavController(this) + .navigate(R.id.action_MainFragment_to_SignInFragment); + return true; + } else { + return super.onOptionsItemSelected(item); + } + } +} 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/NewPostFragment.java similarity index 72% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostActivity.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/NewPostFragment.java index 93a7a6511..9c4411c1d 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/NewPostFragment.java @@ -3,41 +3,47 @@ import android.os.Bundle; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.fragment.NavHostFragment; + import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; -import com.google.firebase.quickstart.database.databinding.ActivityNewPostBinding; +import com.google.firebase.quickstart.database.R; +import com.google.firebase.quickstart.database.databinding.FragmentNewPostBinding; 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; -public class NewPostActivity extends BaseActivity { - - private static final String TAG = "NewPostActivity"; +public class NewPostFragment extends BaseFragment { + private static final String TAG = "NewPostFragment"; private static final String REQUIRED = "Required"; - // [START declare_database_ref] private DatabaseReference mDatabase; - // [END declare_database_ref] - private ActivityNewPostBinding binding; + private FragmentNewPostBinding binding; + @Nullable @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = ActivityNewPostBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentNewPostBinding.inflate(inflater, container, false); + return binding.getRoot(); + } - // [START initialize_database_ref] + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); mDatabase = FirebaseDatabase.getInstance().getReference(); - // [END initialize_database_ref] binding.fabSubmitPost.setOnClickListener(new View.OnClickListener() { @Override @@ -65,22 +71,20 @@ private void submitPost() { // Disable button so there are no multi-posts setEditingEnabled(false); - Toast.makeText(this, "Posting...", Toast.LENGTH_SHORT).show(); + Toast.makeText(getContext(), "Posting...", Toast.LENGTH_SHORT).show(); - // [START single_value_read] final String userId = getUid(); mDatabase.child("users").child(userId).addListenerForSingleValueEvent( new ValueEventListener() { @Override - public void onDataChange(DataSnapshot dataSnapshot) { + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { // Get user value User user = dataSnapshot.getValue(User.class); - // [START_EXCLUDE] if (user == null) { // User is null, error out Log.e(TAG, "User " + userId + " is unexpectedly null"); - Toast.makeText(NewPostActivity.this, + Toast.makeText(getContext(), "Error: could not fetch user.", Toast.LENGTH_SHORT).show(); } else { @@ -88,21 +92,17 @@ public void onDataChange(DataSnapshot dataSnapshot) { writeNewPost(userId, user.username, title, body); } - // Finish this Activity, back to the stream setEditingEnabled(true); - finish(); - // [END_EXCLUDE] + NavHostFragment.findNavController(NewPostFragment.this) + .navigate(R.id.action_NewPostFragment_to_MainFragment); } @Override - public void onCancelled(DatabaseError databaseError) { + public void onCancelled(@NonNull DatabaseError databaseError) { Log.w(TAG, "getUser:onCancelled", databaseError.toException()); - // [START_EXCLUDE] setEditingEnabled(true); - // [END_EXCLUDE] } }); - // [END single_value_read] } private void setEditingEnabled(boolean enabled) { @@ -115,7 +115,6 @@ private void setEditingEnabled(boolean enabled) { } } - // [START write_fan_out] private void writeNewPost(String userId, String username, String title, String body) { // Create new post at /user-posts/$userid/$postid and at // /posts/$postid simultaneously @@ -129,5 +128,4 @@ private void writeNewPost(String userId, String username, String title, String b mDatabase.updateChildren(childUpdates); } - // [END write_fan_out] } 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/PostDetailFragment.java similarity index 83% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailActivity.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/PostDetailFragment.java index e5e9b0722..591aca681 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/PostDetailFragment.java @@ -2,15 +2,17 @@ import android.content.Context; import android.os.Bundle; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.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 androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.google.firebase.database.ChildEventListener; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.DatabaseError; @@ -18,17 +20,18 @@ import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; import com.google.firebase.quickstart.database.R; -import com.google.firebase.quickstart.database.databinding.ActivityPostDetailBinding; +import com.google.firebase.quickstart.database.databinding.FragmentPostDetailBinding; import com.google.firebase.quickstart.database.java.models.Comment; import com.google.firebase.quickstart.database.java.models.Post; import com.google.firebase.quickstart.database.java.models.User; +import com.google.firebase.quickstart.database.java.viewholder.CommentViewHolder; import java.util.ArrayList; import java.util.List; -public class PostDetailActivity extends BaseActivity implements View.OnClickListener { +public class PostDetailFragment extends BaseFragment { - private static final String TAG = "PostDetailActivity"; + private static final String TAG = "PostDetailFragment"; public static final String EXTRA_POST_KEY = "post_key"; @@ -37,16 +40,22 @@ public class PostDetailActivity extends BaseActivity implements View.OnClickList private ValueEventListener mPostListener; private String mPostKey; private CommentAdapter mAdapter; - private ActivityPostDetailBinding binding; + private FragmentPostDetailBinding binding; + + @Nullable @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = ActivityPostDetailBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentPostDetailBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); - // Get post key from intent - mPostKey = getIntent().getStringExtra(EXTRA_POST_KEY); + // Get post key from arguments + mPostKey = requireArguments().getString(EXTRA_POST_KEY); if (mPostKey == null) { throw new IllegalArgumentException("Must pass EXTRA_POST_KEY"); } @@ -57,9 +66,13 @@ protected void onCreate(Bundle savedInstanceState) { mCommentsReference = FirebaseDatabase.getInstance().getReference() .child("post-comments").child(mPostKey); - binding.buttonPostComment.setOnClickListener(this); - binding.recyclerPostComments.setLayoutManager(new LinearLayoutManager(this)); - + binding.buttonPostComment.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + postComment(); + } + }); + binding.recyclerPostComments.setLayoutManager(new LinearLayoutManager(getContext())); } @Override @@ -67,37 +80,31 @@ public void onStart() { super.onStart(); // Add value event listener to the post - // [START post_value_event_listener] ValueEventListener postListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { // Get Post object and use the values to update the UI Post post = dataSnapshot.getValue(Post.class); - // [START_EXCLUDE] binding.postAuthorLayout.postAuthor.setText(post.author); binding.postTextLayout.postTitle.setText(post.title); binding.postTextLayout.postBody.setText(post.body); - // [END_EXCLUDE] } @Override public void onCancelled(DatabaseError databaseError) { // Getting Post failed, log a message Log.w(TAG, "loadPost:onCancelled", databaseError.toException()); - // [START_EXCLUDE] - Toast.makeText(PostDetailActivity.this, "Failed to load post.", + Toast.makeText(getContext(), "Failed to load post.", Toast.LENGTH_SHORT).show(); - // [END_EXCLUDE] } }; mPostReference.addValueEventListener(postListener); - // [END post_value_event_listener] // Keep copy of post listener so we can remove it when app stops mPostListener = postListener; // Listen for comments - mAdapter = new CommentAdapter(this, mCommentsReference); + mAdapter = new CommentAdapter(getContext(), mCommentsReference); binding.recyclerPostComments.setAdapter(mAdapter); } @@ -114,14 +121,6 @@ public void onStop() { mAdapter.cleanupListener(); } - @Override - public void onClick(View v) { - int i = v.getId(); - if (i == R.id.buttonPostComment) { - postComment(); - } - } - private void postComment() { final String uid = getUid(); FirebaseDatabase.getInstance().getReference().child("users").child(uid) @@ -150,19 +149,6 @@ public void onCancelled(DatabaseError databaseError) { }); } - private static class CommentViewHolder extends RecyclerView.ViewHolder { - - public TextView authorView; - public TextView bodyView; - - public CommentViewHolder(View itemView) { - super(itemView); - - authorView = itemView.findViewById(R.id.commentAuthor); - bodyView = itemView.findViewById(R.id.commentBody); - } - } - private static class CommentAdapter extends RecyclerView.Adapter { private Context mContext; @@ -177,7 +163,6 @@ public CommentAdapter(final Context context, DatabaseReference ref) { mDatabaseReference = ref; // Create child event listener - // [START child_event_listener_recycler] ChildEventListener childEventListener = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { @@ -186,12 +171,10 @@ public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) { // A new comment has been added, add it to the displayed list Comment comment = dataSnapshot.getValue(Comment.class); - // [START_EXCLUDE] // Update RecyclerView mCommentIds.add(dataSnapshot.getKey()); mComments.add(comment); notifyItemInserted(mComments.size() - 1); - // [END_EXCLUDE] } @Override @@ -203,7 +186,6 @@ public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) Comment newComment = dataSnapshot.getValue(Comment.class); String commentKey = dataSnapshot.getKey(); - // [START_EXCLUDE] int commentIndex = mCommentIds.indexOf(commentKey); if (commentIndex > -1) { // Replace with the new data @@ -214,7 +196,6 @@ public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) } else { Log.w(TAG, "onChildChanged:unknown_child:" + commentKey); } - // [END_EXCLUDE] } @Override @@ -225,7 +206,6 @@ public void onChildRemoved(DataSnapshot dataSnapshot) { // comment and if so remove it. String commentKey = dataSnapshot.getKey(); - // [START_EXCLUDE] int commentIndex = mCommentIds.indexOf(commentKey); if (commentIndex > -1) { // Remove data from the list @@ -237,7 +217,6 @@ public void onChildRemoved(DataSnapshot dataSnapshot) { } else { Log.w(TAG, "onChildRemoved:unknown_child:" + commentKey); } - // [END_EXCLUDE] } @Override @@ -260,7 +239,6 @@ public void onCancelled(DatabaseError databaseError) { } }; ref.addChildEventListener(childEventListener); - // [END child_event_listener_recycler] // Store reference to listener so it can be removed on app stop mChildEventListener = childEventListener; 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/SignInFragment.java similarity index 77% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInActivity.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/SignInFragment.java index f6b9ab331..90214b683 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/SignInFragment.java @@ -2,14 +2,18 @@ import android.content.Intent; import android.os.Bundle; -import androidx.annotation.NonNull; import android.text.TextUtils; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; -import android.widget.EditText; +import android.view.ViewGroup; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.navigation.Navigation; +import androidx.navigation.fragment.NavHostFragment; + import com.google.android.gms.tasks.OnCompleteListener; import com.google.android.gms.tasks.Task; import com.google.firebase.auth.AuthResult; @@ -18,24 +22,28 @@ 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.databinding.ActivitySignInBinding; +import com.google.firebase.quickstart.database.databinding.FragmentSignInBinding; import com.google.firebase.quickstart.database.java.models.User; -public class SignInActivity extends BaseActivity implements View.OnClickListener { +public class SignInFragment extends BaseFragment implements View.OnClickListener { - private static final String TAG = "SignInActivity"; + private static final String TAG = "SignInFragment"; private DatabaseReference mDatabase; private FirebaseAuth mAuth; - private ActivitySignInBinding binding; + private FragmentSignInBinding binding; + @Nullable @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = ActivitySignInBinding.inflate(getLayoutInflater()); - setContentView(binding.getRoot()); + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + binding = FragmentSignInBinding.inflate(inflater, container, false); + return binding.getRoot(); + } + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); mDatabase = FirebaseDatabase.getInstance().getReference(); mAuth = FirebaseAuth.getInstance(); @@ -68,7 +76,7 @@ private void signIn() { String password = binding.fieldPassword.getText().toString(); mAuth.signInWithEmailAndPassword(email, password) - .addOnCompleteListener(this, new OnCompleteListener() { + .addOnCompleteListener(getActivity(), new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { Log.d(TAG, "signIn:onComplete:" + task.isSuccessful()); @@ -77,7 +85,7 @@ public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { onAuthSuccess(task.getResult().getUser()); } else { - Toast.makeText(SignInActivity.this, "Sign In Failed", + Toast.makeText(getContext(), "Sign In Failed", Toast.LENGTH_SHORT).show(); } } @@ -95,7 +103,7 @@ private void signUp() { String password = binding.fieldPassword.getText().toString(); mAuth.createUserWithEmailAndPassword(email, password) - .addOnCompleteListener(this, new OnCompleteListener() { + .addOnCompleteListener(getActivity(), new OnCompleteListener() { @Override public void onComplete(@NonNull Task task) { Log.d(TAG, "createUser:onComplete:" + task.isSuccessful()); @@ -104,7 +112,7 @@ public void onComplete(@NonNull Task task) { if (task.isSuccessful()) { onAuthSuccess(task.getResult().getUser()); } else { - Toast.makeText(SignInActivity.this, "Sign Up Failed", + Toast.makeText(getContext(), "Sign Up Failed", Toast.LENGTH_SHORT).show(); } } @@ -117,9 +125,8 @@ private void onAuthSuccess(FirebaseUser user) { // Write new user writeNewUser(user.getUid(), username, user.getEmail()); - // Go to MainActivity - startActivity(new Intent(SignInActivity.this, MainActivity.class)); - finish(); + // Go to MainFragment + NavHostFragment.findNavController(this).navigate(R.id.action_SignInFragment_to_MainFragment); } private String usernameFromEmail(String email) { @@ -149,15 +156,12 @@ private boolean validateForm() { return result; } - // [START basic_write] private void writeNewUser(String userId, String name, String email) { User user = new User(name, email); mDatabase.child("users").child(userId).setValue(user); } - // [END basic_write] - @Override public void onClick(View v) { int i = v.getId(); if (i == R.id.buttonSignIn) { diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyPostsFragment.java similarity index 85% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyPostsFragment.java index fbec06163..fe28d34a1 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyPostsFragment.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyPostsFragment.java @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.java.fragment; +package com.google.firebase.quickstart.database.java.listfragments; 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/java/fragment/MyTopPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyTopPostsFragment.java similarity index 79% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyTopPostsFragment.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyTopPostsFragment.java index 8600d1d32..5f49ee2cb 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/MyTopPostsFragment.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/MyTopPostsFragment.java @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.java.fragment; +package com.google.firebase.quickstart.database.java.listfragments; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.Query; @@ -9,12 +9,10 @@ public MyTopPostsFragment() {} @Override public Query getQuery(DatabaseReference databaseReference) { - // [START my_top_posts_query] // My top posts by number of stars String myUserId = getUid(); Query myTopPostsQuery = databaseReference.child("user-posts").child(myUserId) .orderByChild("starCount"); - // [END my_top_posts_query] return myTopPostsQuery; } diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/PostListFragment.java similarity index 90% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/PostListFragment.java index ef4bf332c..cef758620 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/PostListFragment.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/PostListFragment.java @@ -1,6 +1,5 @@ -package com.google.firebase.quickstart.database.java.fragment; +package com.google.firebase.quickstart.database.java.listfragments; -import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -8,6 +7,8 @@ import android.view.ViewGroup; import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -22,7 +23,7 @@ import com.google.firebase.database.Query; import com.google.firebase.database.Transaction; import com.google.firebase.quickstart.database.R; -import com.google.firebase.quickstart.database.java.PostDetailActivity; +import com.google.firebase.quickstart.database.java.PostDetailFragment; import com.google.firebase.quickstart.database.java.models.Post; import com.google.firebase.quickstart.database.java.viewholder.PostViewHolder; @@ -90,10 +91,12 @@ protected void onBindViewHolder(PostViewHolder viewHolder, int position, final P viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - // Launch PostDetailActivity - Intent intent = new Intent(getActivity(), PostDetailActivity.class); - intent.putExtra(PostDetailActivity.EXTRA_POST_KEY, postKey); - startActivity(intent); + // Launch PostDetailFragment + NavController navController = Navigation.findNavController(requireActivity(), + R.id.nav_host_fragment); + Bundle args = new Bundle(); + args.putString(PostDetailFragment.EXTRA_POST_KEY, postKey); + navController.navigate(R.id.action_MainFragment_to_PostDetailFragment, args); } }); diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/RecentPostsFragment.java similarity index 89% rename from database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java rename to database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/RecentPostsFragment.java index 48c936d30..6f8c48bcc 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/fragment/RecentPostsFragment.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/listfragments/RecentPostsFragment.java @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.java.fragment; +package com.google.firebase.quickstart.database.java.listfragments; 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/java/models/Comment.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java index f670f3900..5db6f9b3f 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Comment.java @@ -2,7 +2,6 @@ import com.google.firebase.database.IgnoreExtraProperties; -// [START comment_class] @IgnoreExtraProperties public class Comment { @@ -21,4 +20,3 @@ public Comment(String uid, String author, String text) { } } -// [END comment_class] diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java index 0c42d38fd..7223f2c94 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/Post.java @@ -6,7 +6,6 @@ import java.util.HashMap; import java.util.Map; -// [START post_class] @IgnoreExtraProperties public class Post { @@ -28,7 +27,6 @@ public Post(String uid, String author, String title, String body) { this.body = body; } - // [START post_to_map] @Exclude public Map toMap() { HashMap result = new HashMap<>(); @@ -41,7 +39,5 @@ public Map toMap() { return result; } - // [END post_to_map] } -// [END post_class] diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java index d8c241dce..43c6f39ac 100644 --- a/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/models/User.java @@ -2,7 +2,6 @@ import com.google.firebase.database.IgnoreExtraProperties; -// [START blog_user_class] @IgnoreExtraProperties public class User { @@ -19,4 +18,3 @@ public User(String username, String email) { } } -// [END blog_user_class] diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/CommentViewHolder.java b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/CommentViewHolder.java new file mode 100644 index 000000000..fefad76dc --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/java/viewholder/CommentViewHolder.java @@ -0,0 +1,19 @@ +package com.google.firebase.quickstart.database.java.viewholder; + +import android.view.View; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.google.firebase.quickstart.database.R; + +public class CommentViewHolder extends RecyclerView.ViewHolder { + public TextView authorView; + public TextView bodyView; + + public CommentViewHolder(View itemView) { + super(itemView); + 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/kotlin/BaseActivity.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseFragment.kt similarity index 78% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseActivity.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/BaseFragment.kt index 24e57bda1..c70be7781 100644 --- 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/BaseFragment.kt @@ -2,19 +2,18 @@ package com.google.firebase.quickstart.database.kotlin import android.view.View import android.widget.ProgressBar -import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment import com.google.firebase.auth.ktx.auth import com.google.firebase.ktx.Firebase -open class BaseActivity : AppCompatActivity() { - +open class BaseFragment : Fragment() { private var progressBar: ProgressBar? = null val uid: String get() = Firebase.auth.currentUser!!.uid fun setProgressBar(resId: Int) { - progressBar = findViewById(resId) + progressBar = view?.findViewById(resId) } fun showProgressBar() { @@ -24,4 +23,4 @@ open class BaseActivity : AppCompatActivity() { fun hideProgressBar() { progressBar?.visibility = View.INVISIBLE } -} +} \ No newline at end of file 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 index 003db32b0..c8d206807 100644 --- 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 @@ -1,82 +1,36 @@ package com.google.firebase.quickstart.database.kotlin -import android.content.Intent import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentPagerAdapter -import com.google.firebase.auth.ktx.auth -import com.google.firebase.ktx.Firebase +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isGone +import androidx.core.view.isVisible +import androidx.navigation.findNavController import com.google.firebase.quickstart.database.R import com.google.firebase.quickstart.database.databinding.ActivityMainBinding -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 -class MainActivity : BaseActivity() { +class MainActivity : AppCompatActivity() { - private lateinit var pagerAdapter: FragmentPagerAdapter private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - - // Create the adapter that will return a fragment for each section - pagerAdapter = object : FragmentPagerAdapter(supportFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { - 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. - with(binding) { - container.adapter = pagerAdapter - tabs.setupWithViewPager(container) - - // Button launches NewPostActivity - fabNewPost.setOnClickListener { - startActivity(Intent(this@MainActivity, NewPostActivity::class.java)) + val toolbar = binding.toolbar + setSupportActionBar(toolbar) + + val fab = binding.fab + val navController = findNavController(R.id.nav_host_fragment) + navController.setGraph(R.navigation.nav_graph_kotlin) + navController.addOnDestinationChangedListener { _, destination, _ -> + if (destination.id == R.id.MainFragment) { + fab.isVisible = true + fab.setOnClickListener { + navController.navigate(R.id.action_MainFragment_to_NewPostFragment) + } + } else { + fab.isGone = true } } } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { - menuInflater.inflate(R.menu.menu_main, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return if (item.itemId == R.id.action_logout) { - Firebase.auth.signOut() - startActivity(Intent(this, SignInActivity::class.java)) - finish() - true - } else { - super.onOptionsItemSelected(item) - } - } - - companion object { - - private const val TAG = "MainActivity" - } -} +} \ No newline at end of file diff --git a/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainFragment.kt new file mode 100644 index 000000000..3962fa165 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/MainFragment.kt @@ -0,0 +1,80 @@ +package com.google.firebase.quickstart.database.kotlin + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentPagerAdapter +import androidx.navigation.fragment.findNavController +import com.google.firebase.auth.ktx.auth +import com.google.firebase.ktx.Firebase +import com.google.firebase.quickstart.database.R +import com.google.firebase.quickstart.database.databinding.FragmentMainBinding +import com.google.firebase.quickstart.database.kotlin.listfragments.MyPostsFragment +import com.google.firebase.quickstart.database.kotlin.listfragments.MyTopPostsFragment +import com.google.firebase.quickstart.database.kotlin.listfragments.RecentPostsFragment + +class MainFragment : Fragment() { + private var _binding: FragmentMainBinding? = null + private val binding get() = _binding!! + + private lateinit var pagerAdapter: FragmentPagerAdapter + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + _binding = FragmentMainBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setHasOptionsMenu(true) + + // Create the adapter that will return a fragment for each section + pagerAdapter = object : FragmentPagerAdapter(parentFragmentManager, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + 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) = fragments[position] + + override fun getCount() = fragments.size + + override fun getPageTitle(position: Int) = fragmentNames[position] + } + + // Set up the ViewPager with the sections adapter. + with(binding) { + container.adapter = pagerAdapter + tabs.setupWithViewPager(container) + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + inflater.inflate(R.menu.menu_main, menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + return if (item.itemId == R.id.action_logout) { + Firebase.auth.signOut() + findNavController().navigate(R.id.action_MainFragment_to_SignInFragment) + true + } else { + super.onOptionsItemSelected(item) + } + } + + override fun onDestroy() { + super.onDestroy() + _binding = null + } +} \ No newline at end of file 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/NewPostFragment.kt similarity index 75% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostActivity.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/NewPostFragment.kt index 70482dde5..b79067b3d 100644 --- 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/NewPostFragment.kt @@ -3,7 +3,11 @@ package com.google.firebase.quickstart.database.kotlin import android.os.Bundle import android.text.TextUtils import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import android.widget.Toast +import androidx.navigation.fragment.findNavController import com.google.firebase.database.DataSnapshot import com.google.firebase.database.DatabaseError import com.google.firebase.database.DatabaseReference @@ -11,25 +15,26 @@ import com.google.firebase.database.ValueEventListener import com.google.firebase.database.ktx.database import com.google.firebase.database.ktx.getValue import com.google.firebase.ktx.Firebase -import com.google.firebase.quickstart.database.databinding.ActivityNewPostBinding +import com.google.firebase.quickstart.database.R +import com.google.firebase.quickstart.database.databinding.FragmentNewPostBinding import com.google.firebase.quickstart.database.kotlin.models.Post import com.google.firebase.quickstart.database.kotlin.models.User -class NewPostActivity : BaseActivity() { +class NewPostFragment : BaseFragment() { + private var _binding: FragmentNewPostBinding? = null + private val binding get() = _binding!! - // [START declare_database_ref] private lateinit var database: DatabaseReference - // [END declare_database_ref] - private lateinit var binding: ActivityNewPostBinding - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityNewPostBinding.inflate(layoutInflater) - setContentView(binding.root) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + _binding = FragmentNewPostBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - // [START initialize_database_ref] database = Firebase.database.reference - // [END initialize_database_ref] binding.fabSubmitPost.setOnClickListener { submitPost() } } @@ -52,9 +57,8 @@ class NewPostActivity : BaseActivity() { // Disable button so there are no multi-posts setEditingEnabled(false) - Toast.makeText(this, "Posting...", Toast.LENGTH_SHORT).show() + Toast.makeText(context, "Posting...", Toast.LENGTH_SHORT).show() - // [START single_value_read] val userId = uid database.child("users").child(userId).addListenerForSingleValueEvent( object : ValueEventListener { @@ -62,11 +66,10 @@ class NewPostActivity : BaseActivity() { // Get user value val user = dataSnapshot.getValue() - // [START_EXCLUDE] if (user == null) { // User is null, error out Log.e(TAG, "User $userId is unexpectedly null") - Toast.makeText(baseContext, + Toast.makeText(context, "Error: could not fetch user.", Toast.LENGTH_SHORT).show() } else { @@ -74,20 +77,15 @@ class NewPostActivity : BaseActivity() { writeNewPost(userId, user.username.toString(), title, body) } - // Finish this Activity, back to the stream setEditingEnabled(true) - finish() - // [END_EXCLUDE] + findNavController().navigate(R.id.action_NewPostFragment_to_MainFragment) } 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) { @@ -102,7 +100,6 @@ class NewPostActivity : BaseActivity() { } } - // [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 @@ -122,11 +119,14 @@ class NewPostActivity : BaseActivity() { database.updateChildren(childUpdates) } - // [END write_fan_out] - companion object { + override fun onDestroy() { + super.onDestroy() + _binding = null + } - private const val TAG = "NewPostActivity" + companion object { + private const val TAG = "NewPostFragment" private const val REQUIRED = "Required" } -} +} \ No newline at end of file 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/PostDetailFragment.kt similarity index 80% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailActivity.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/PostDetailFragment.kt index 9ead0911b..546e47db1 100644 --- 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/PostDetailFragment.kt @@ -6,26 +6,27 @@ 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 androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.google.firebase.database.ChildEventListener -import com.google.firebase.database.DataSnapshot import com.google.firebase.database.DatabaseError import com.google.firebase.database.DatabaseReference +import com.google.firebase.database.DataSnapshot import com.google.firebase.database.ValueEventListener import com.google.firebase.database.ktx.database import com.google.firebase.database.ktx.getValue import com.google.firebase.ktx.Firebase import com.google.firebase.quickstart.database.R -import com.google.firebase.quickstart.database.databinding.ActivityPostDetailBinding +import com.google.firebase.quickstart.database.databinding.FragmentPostDetailBinding 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 com.google.firebase.quickstart.database.kotlin.viewholder.CommentViewHolder +import java.lang.IllegalArgumentException import java.util.ArrayList -class PostDetailActivity : BaseActivity(), View.OnClickListener { +class PostDetailFragment : BaseFragment() { private lateinit var postKey: String private lateinit var postReference: DatabaseReference @@ -34,15 +35,19 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { private var postListener: ValueEventListener? = null private var adapter: CommentAdapter? = null - private lateinit var binding: ActivityPostDetailBinding + private var _binding: FragmentPostDetailBinding? = null + private val binding get() = _binding!! + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + _binding = FragmentPostDetailBinding.inflate(inflater, container, false) + return binding.root + } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivityPostDetailBinding.inflate(layoutInflater) - setContentView(binding.root) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - // Get post key from intent - postKey = intent.getStringExtra(EXTRA_POST_KEY) + // Get post key from arguments + postKey = requireArguments().getString(EXTRA_POST_KEY) ?: throw IllegalArgumentException("Must pass EXTRA_POST_KEY") // Initialize Database @@ -53,21 +58,19 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { // Initialize Views with(binding) { - buttonPostComment.setOnClickListener(this@PostDetailActivity) - recyclerPostComments.layoutManager = LinearLayoutManager(this@PostDetailActivity) + buttonPostComment.setOnClickListener { postComment() } + recyclerPostComments.layoutManager = LinearLayoutManager(context) } } - public override fun onStart() { + 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() - // [START_EXCLUDE] post?.let { binding.postAuthorLayout.postAuthor.text = it.author with(binding.postTextLayout) { @@ -75,30 +78,26 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { 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.makeText(context, "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) + adapter = CommentAdapter(requireContext(), commentsReference) binding.recyclerPostComments.adapter = adapter } - public override fun onStop() { + override fun onStop() { super.onStop() // Remove post value event listener @@ -110,23 +109,13 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { adapter?.cleanupListener() } - override fun onClick(v: View) { - val i = v.id - if (i == R.id.buttonPostComment) { - postComment() - } - } - private fun postComment() { val uid = uid Firebase.database.reference.child("users").child(uid) .addListenerForSingleValueEvent(object : ValueEventListener { override fun onDataChange(dataSnapshot: DataSnapshot) { // Get user information - val user = dataSnapshot.getValue() - if (user == null) { - return - } + val user = dataSnapshot.getValue() ?: return val authorName = user.username @@ -146,17 +135,9 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { }) } - private class CommentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - - fun bind(comment: Comment) { - itemView.findViewById(R.id.commentAuthor).text = comment.author - itemView.findViewById(R.id.commentBody).text = comment.text - } - } - private class CommentAdapter( - private val context: Context, - private val databaseReference: DatabaseReference + private val context: Context, + private val databaseReference: DatabaseReference ) : RecyclerView.Adapter() { private val childEventListener: ChildEventListener? @@ -167,7 +148,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { 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!!) @@ -175,12 +155,10 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { // A new comment has been added, add it to the displayed list val comment = dataSnapshot.getValue() - // [START_EXCLUDE] // Update RecyclerView commentIds.add(dataSnapshot.key!!) comments.add(comment!!) notifyItemInserted(comments.size - 1) - // [END_EXCLUDE] } override fun onChildChanged(dataSnapshot: DataSnapshot, previousChildName: String?) { @@ -191,7 +169,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { val newComment = dataSnapshot.getValue() val commentKey = dataSnapshot.key - // [START_EXCLUDE] val commentIndex = commentIds.indexOf(commentKey) if (commentIndex > -1 && newComment != null) { // Replace with the new data @@ -202,7 +179,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { } else { Log.w(TAG, "onChildChanged:unknown_child: $commentKey") } - // [END_EXCLUDE] } override fun onChildRemoved(dataSnapshot: DataSnapshot) { @@ -212,7 +188,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { // 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 @@ -224,7 +199,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { } else { Log.w(TAG, "onChildRemoved:unknown_child:" + commentKey!!) } - // [END_EXCLUDE] } override fun onChildMoved(dataSnapshot: DataSnapshot, previousChildName: String?) { @@ -245,7 +219,6 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { } } databaseReference.addChildEventListener(childEventListener) - // [END child_event_listener_recycler] // Store reference to listener so it can be removed on app stop this.childEventListener = childEventListener @@ -270,9 +243,13 @@ class PostDetailActivity : BaseActivity(), View.OnClickListener { } } - companion object { + override fun onDestroy() { + super.onDestroy() + _binding = null + } - private const val TAG = "PostDetailActivity" + companion object { + private const val TAG = "PostDetailFragment" const val EXTRA_POST_KEY = "post_key" } -} +} \ No newline at end of file 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/SignInFragment.kt similarity index 72% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInActivity.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/SignInFragment.kt index f90e0708e..0c198bdb2 100644 --- 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/SignInFragment.kt @@ -1,11 +1,13 @@ 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.LayoutInflater import android.view.View +import android.view.ViewGroup import android.widget.Toast +import androidx.navigation.fragment.findNavController import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.FirebaseUser import com.google.firebase.auth.ktx.auth @@ -13,19 +15,23 @@ import com.google.firebase.database.DatabaseReference import com.google.firebase.database.ktx.database import com.google.firebase.ktx.Firebase import com.google.firebase.quickstart.database.R -import com.google.firebase.quickstart.database.databinding.ActivitySignInBinding +import com.google.firebase.quickstart.database.databinding.FragmentSignInBinding import com.google.firebase.quickstart.database.kotlin.models.User -class SignInActivity : BaseActivity(), View.OnClickListener { +class SignInFragment : BaseFragment() { + private var _binding: FragmentSignInBinding? = null + private val binding get() = _binding!! private lateinit var database: DatabaseReference private lateinit var auth: FirebaseAuth - private lateinit var binding: ActivitySignInBinding - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - binding = ActivitySignInBinding.inflate(layoutInflater) - setContentView(binding.root) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + _binding = FragmentSignInBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) database = Firebase.database.reference auth = Firebase.auth @@ -34,15 +40,15 @@ class SignInActivity : BaseActivity(), View.OnClickListener { // Click listeners with(binding) { - buttonSignIn.setOnClickListener(this@SignInActivity) - buttonSignUp.setOnClickListener(this@SignInActivity) + buttonSignIn.setOnClickListener { signIn() } + buttonSignUp.setOnClickListener { signUp() } } } - public override fun onStart() { + override fun onStart() { super.onStart() - // Check auth on Activity start + // Check auth on Fragment start auth.currentUser?.let { onAuthSuccess(it) } @@ -59,14 +65,14 @@ class SignInActivity : BaseActivity(), View.OnClickListener { val password = binding.fieldPassword.text.toString() auth.signInWithEmailAndPassword(email, password) - .addOnCompleteListener(this) { task -> + .addOnCompleteListener(requireActivity()) { task -> Log.d(TAG, "signIn:onComplete:" + task.isSuccessful) hideProgressBar() if (task.isSuccessful) { onAuthSuccess(task.result?.user!!) } else { - Toast.makeText(baseContext, "Sign In Failed", + Toast.makeText(context, "Sign In Failed", Toast.LENGTH_SHORT).show() } } @@ -83,14 +89,14 @@ class SignInActivity : BaseActivity(), View.OnClickListener { val password = binding.fieldPassword.text.toString() auth.createUserWithEmailAndPassword(email, password) - .addOnCompleteListener(this) { task -> + .addOnCompleteListener(requireActivity()) { task -> Log.d(TAG, "createUser:onComplete:" + task.isSuccessful) hideProgressBar() if (task.isSuccessful) { onAuthSuccess(task.result?.user!!) } else { - Toast.makeText(baseContext, "Sign Up Failed", + Toast.makeText(context, "Sign Up Failed", Toast.LENGTH_SHORT).show() } } @@ -102,9 +108,8 @@ class SignInActivity : BaseActivity(), View.OnClickListener { // Write new user writeNewUser(user.uid, username, user.email) - // Go to MainActivity - startActivity(Intent(this@SignInActivity, MainActivity::class.java)) - finish() + // Go to MainFragment + findNavController().navigate(R.id.action_SignInFragment_to_MainFragment) } private fun usernameFromEmail(email: String): String { @@ -134,24 +139,17 @@ class SignInActivity : BaseActivity(), View.OnClickListener { 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() - } + + override fun onDestroy() { + super.onDestroy() + _binding = null } companion object { - - private const val TAG = "SignInActivity" + private const val TAG = "SignInFragment" } -} +} \ No newline at end of file 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/listfragments/MyPostsFragment.kt similarity index 82% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyPostsFragment.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/listfragments/MyPostsFragment.kt index 0ed609cc4..d13860bb1 100644 --- 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/listfragments/MyPostsFragment.kt @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.kotlin.fragment +package com.google.firebase.quickstart.database.kotlin.listfragments 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/kotlin/fragment/MyTopPostsFragment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/listfragments/MyTopPostsFragment.kt similarity index 74% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/MyTopPostsFragment.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/listfragments/MyTopPostsFragment.kt index 890905551..51de89682 100644 --- 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/listfragments/MyTopPostsFragment.kt @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.kotlin.fragment +package com.google.firebase.quickstart.database.kotlin.listfragments import com.google.firebase.database.DatabaseReference import com.google.firebase.database.Query @@ -6,10 +6,8 @@ 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/listfragments/PostListFragment.kt similarity index 91% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/PostListFragment.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/listfragments/PostListFragment.kt index 102a3d814..3e9dcba16 100644 --- 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/listfragments/PostListFragment.kt @@ -1,12 +1,13 @@ -package com.google.firebase.quickstart.database.kotlin.fragment +package com.google.firebase.quickstart.database.kotlin.listfragments -import android.content.Intent import android.os.Bundle import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.core.os.bundleOf import androidx.fragment.app.Fragment +import androidx.navigation.findNavController import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.firebase.ui.database.FirebaseRecyclerAdapter @@ -21,7 +22,7 @@ import com.google.firebase.database.Transaction import com.google.firebase.database.ktx.database import com.google.firebase.ktx.Firebase import com.google.firebase.quickstart.database.R -import com.google.firebase.quickstart.database.kotlin.PostDetailActivity +import com.google.firebase.quickstart.database.kotlin.PostDetailFragment import com.google.firebase.quickstart.database.kotlin.models.Post import com.google.firebase.quickstart.database.kotlin.viewholder.PostViewHolder @@ -85,17 +86,17 @@ abstract class PostListFragment : Fragment() { // 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) + // Launch PostDetailFragment + val navController = requireActivity().findNavController(R.id.nav_host_fragment) + val args = bundleOf(PostDetailFragment.EXTRA_POST_KEY to postKey) + navController.navigate(R.id.action_MainFragment_to_PostDetailFragment, args) } // 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 { + viewHolder.bindToPost(model) { // 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!!) @@ -103,7 +104,7 @@ abstract class PostListFragment : Fragment() { // Run two transactions onStarClicked(globalPostRef) onStarClicked(userPostRef) - }) + } } } recycler.adapter = adapter 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/listfragments/RecentPostsFragment.kt similarity index 87% rename from database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/fragment/RecentPostsFragment.kt rename to database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/listfragments/RecentPostsFragment.kt index b48382f1e..e64488e13 100644 --- 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/listfragments/RecentPostsFragment.kt @@ -1,4 +1,4 @@ -package com.google.firebase.quickstart.database.kotlin.fragment +package com.google.firebase.quickstart.database.kotlin.listfragments 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/kotlin/models/Comment.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/models/Comment.kt index 3397ff1b3..73043419e 100644 --- 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 @@ -2,11 +2,9 @@ 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 index b081f98d5..b583973fa 100644 --- 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 @@ -4,7 +4,6 @@ import com.google.firebase.database.Exclude import com.google.firebase.database.IgnoreExtraProperties import java.util.HashMap -// [START post_class] @IgnoreExtraProperties data class Post( var uid: String? = "", @@ -15,7 +14,6 @@ data class Post( var stars: MutableMap = HashMap() ) { - // [START post_to_map] @Exclude fun toMap(): Map { return mapOf( @@ -27,6 +25,4 @@ data class Post( "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 index d79ad7be4..af3bdb069 100644 --- 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 @@ -2,10 +2,8 @@ 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/CommentViewHolder.kt b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/CommentViewHolder.kt new file mode 100644 index 000000000..07be868c3 --- /dev/null +++ b/database/app/src/main/java/com/google/firebase/quickstart/database/kotlin/viewholder/CommentViewHolder.kt @@ -0,0 +1,14 @@ +package com.google.firebase.quickstart.database.kotlin.viewholder + +import android.view.View +import android.widget.TextView +import androidx.recyclerview.widget.RecyclerView +import com.google.firebase.quickstart.database.R +import com.google.firebase.quickstart.database.kotlin.models.Comment + +class CommentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + fun bind(comment: Comment) { + itemView.findViewById(R.id.commentAuthor).text = comment.author + itemView.findViewById(R.id.commentBody).text = comment.text + } +} \ No newline at end of file diff --git a/database/app/src/main/res/layout/activity_main.xml b/database/app/src/main/res/layout/activity_main.xml index eca31e389..85b0fa97e 100644 --- a/database/app/src/main/res/layout/activity_main.xml +++ b/database/app/src/main/res/layout/activity_main.xml @@ -1,34 +1,46 @@ - - + android:theme="@style/AppTheme.AppBarOverlay"> - + + + + android:layout_gravity="bottom|end" + android:layout_margin="@dimen/fab_margin" + app:srcCompat="@drawable/ic_image_edit" /> + + + + + - + \ No newline at end of file diff --git a/database/app/src/main/res/layout/fragment_main.xml b/database/app/src/main/res/layout/fragment_main.xml new file mode 100644 index 000000000..75c240ab8 --- /dev/null +++ b/database/app/src/main/res/layout/fragment_main.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/database/app/src/main/res/layout/fragment_new_post.xml b/database/app/src/main/res/layout/fragment_new_post.xml new file mode 100644 index 000000000..2cb1c34f4 --- /dev/null +++ b/database/app/src/main/res/layout/fragment_new_post.xml @@ -0,0 +1,54 @@ + + + + + + + + + + diff --git a/database/app/src/main/res/layout/fragment_post_detail.xml b/database/app/src/main/res/layout/fragment_post_detail.xml new file mode 100644 index 000000000..420dfe57f --- /dev/null +++ b/database/app/src/main/res/layout/fragment_post_detail.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + diff --git a/database/app/src/main/res/layout/fragment_sign_in.xml b/database/app/src/main/res/layout/fragment_sign_in.xml new file mode 100644 index 000000000..93c9668e7 --- /dev/null +++ b/database/app/src/main/res/layout/fragment_sign_in.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + +