WIP followers

This commit is contained in:
Erik Cavazos 2023-08-12 00:59:02 -06:00
parent 1d358a403b
commit 94d9998f67
17 changed files with 290 additions and 69 deletions

104
.idea/navEditor.xml generated
View File

@ -37,6 +37,40 @@
</LayoutPositions>
</value>
</entry>
<entry key="followers_navigation.xml">
<value>
<LayoutPositions>
<option name="myPositions">
<map>
<entry key="followersFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-243" />
<option name="y" value="41" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="followingFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-44" />
<option name="y" value="35" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="home_navigation.xml">
<value>
<LayoutPositions>
@ -135,8 +169,8 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="192" />
<option name="y" value="-141" />
<option name="x" value="230" />
<option name="y" value="1436" />
</Point>
</option>
</LayoutPositions>
@ -147,20 +181,44 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="191" />
<option name="y" value="-446" />
<option name="x" value="230" />
<option name="y" value="12" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="discussionsFragment">
<entry key="imagesFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-374" />
<option name="y" value="-122" />
<option name="x" value="230" />
<option name="y" value="1792" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="mainFollowersFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="230" />
<option name="y" value="1080" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="mainFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="103" />
</Point>
</option>
<option name="myPositions">
@ -200,37 +258,13 @@
</LayoutPositions>
</value>
</entry>
<entry key="imagesFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="198" />
<option name="y" value="164" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="mainFollowersFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-266" />
<option name="y" value="274" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="reportProfileFragment">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-83" />
<option name="y" value="327" />
<option name="x" value="230" />
<option name="y" value="368" />
</Point>
</option>
</LayoutPositions>
@ -241,8 +275,8 @@
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="-123" />
<option name="y" value="-402" />
<option name="x" value="230" />
<option name="y" value="724" />
</Point>
</option>
</LayoutPositions>

View File

@ -0,0 +1,16 @@
package com.isolaatti.followers.presentation
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.isolaatti.profile.data.remote.ProfileListItemDto
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class FollowersViewModel @Inject constructor() : ViewModel() {
val followers: MutableLiveData<List<ProfileListItemDto>> = MutableLiveData()
val followings: MutableLiveData<List<ProfileListItemDto>> = MutableLiveData()
}

View File

@ -0,0 +1,18 @@
package com.isolaatti.followers.presentation
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.isolaatti.followers.ui.FollowersFragment
import com.isolaatti.followers.ui.FollowingFragment
class FollowersViewPagerAdapter(fragment: Fragment) : FragmentStateAdapter(fragment) {
override fun getItemCount(): Int = 2
override fun createFragment(position: Int): Fragment {
if(position == 0) {
return FollowersFragment()
}
return FollowingFragment()
}
}

View File

@ -0,0 +1,24 @@
package com.isolaatti.followers.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.isolaatti.databinding.FragmentFollowersBinding
import com.isolaatti.followers.presentation.FollowersViewModel
class FollowersFragment : Fragment() {
private lateinit var binding: FragmentFollowersBinding
private val viewModel: FollowersViewModel by viewModels({ requireParentFragment() })
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentFollowersBinding.inflate(inflater)
return binding.root
}
}

View File

@ -0,0 +1,24 @@
package com.isolaatti.followers.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.isolaatti.databinding.FragmentFollowersBinding
import com.isolaatti.followers.presentation.FollowersViewModel
class FollowingFragment : Fragment() {
private lateinit var binding: FragmentFollowersBinding
private val viewModel: FollowersViewModel by viewModels({ requireParentFragment() })
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentFollowersBinding.inflate(inflater)
return binding.root
}
}

View File

@ -0,0 +1,43 @@
package com.isolaatti.followers.ui
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.tabs.TabLayoutMediator
import com.isolaatti.R
import com.isolaatti.databinding.FragmentFollowersMainBinding
import com.isolaatti.followers.presentation.FollowersViewModel
import com.isolaatti.followers.presentation.FollowersViewPagerAdapter
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainFollowersFragment : Fragment() {
private lateinit var binding: FragmentFollowersMainBinding
private val viewModel: FollowersViewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentFollowersMainBinding.inflate(inflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.viewPagerFollowersMain.adapter = FollowersViewPagerAdapter(this)
TabLayoutMediator(binding.tabLayoutFollowers, binding.viewPagerFollowersMain) { tab, position ->
when(position) {
0 -> tab.text = getText(R.string.followers)
1 -> tab.text = getText(R.string.followings)
}
}.attach()
}
}

View File

@ -3,7 +3,6 @@ package com.isolaatti.home
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
@ -14,7 +13,6 @@ import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import com.isolaatti.BuildConfig
@ -31,7 +29,6 @@ import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.posting.posts.presentation.UpdateEvent
import com.isolaatti.posting.posts.ui.CreatePostActivity
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.settings.ui.SettingsActivity
@ -201,7 +198,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
override fun onOptions(postId: Long) {
optionsViewModel.setOptions(Options.postOptions, CALLER_ID)
optionsViewModel.setOptions(Options.myPostOptions, CALLER_ID)
val modalBottomSheet = BottomSheetPostOptionsFragment()
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
}

View File

@ -4,7 +4,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
@ -12,9 +11,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.dialog.MaterialDialogs
import com.isolaatti.R
import com.isolaatti.databinding.BottomSheetPostCommentsBinding
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
@ -120,7 +116,7 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
override fun onOptions(postId: Long) {
optionsViewModel.setOptions(Options.commentOptions, CALLER_ID)
optionsViewModel.setOptions(Options.myCommentOptions, CALLER_ID)
val fragment = BottomSheetPostOptionsFragment()
fragment.show(parentFragmentManager, BottomSheetPostOptionsFragment.TAG)
}

View File

@ -21,15 +21,23 @@ data class Options(
}
companion object {
val myPostOptions = Options(R.string.post_options_title, listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
val postOptions = Options(R.string.post_options_title, listOf(
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
val myCommentOptions = Options(R.string.post_options_title, listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
val commentOptions = Options(R.string.post_options_title, listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
}

View File

@ -1,8 +0,0 @@
package com.isolaatti.profile.ui
import androidx.fragment.app.Fragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainFollowersFragment : Fragment() {
}

View File

@ -5,12 +5,16 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.core.content.res.ResourcesCompat.ThemeCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.R.color.m3_icon_button_icon_color_selector
import com.google.android.material.button.MaterialButton
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.databinding.FragmentDiscussionsBinding
@ -51,7 +55,6 @@ class ProfileMainFragment : Fragment() {
private var scrollRange = -1
private var isShow = false
private val profileObserver = Observer<UserProfileDto> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
@ -60,6 +63,12 @@ class ProfileMainFragment : Fragment() {
title = profile.name
viewBinding.textViewUsername.text = profile.name
viewBinding.textViewDescription.text = profile.descriptionText
viewBinding.goToFollowersBtn.text = getString(
R.string.go_to_followers_btn_text,
profile.numberOfFollowers.toString(),
profile.numberOfFollowing.toString()
)
}
private val postsObserver: Observer<Pair<FeedDto?, UpdateEvent>?> = Observer {
@ -74,18 +83,22 @@ class ProfileMainFragment : Fragment() {
FollowingState.FollowingThisUser -> {
viewBinding.textViewFollowingState.setText(R.string.following_user)
viewBinding.followButton.setText(R.string.unfollow)
viewBinding.followButton.isChecked = true
}
FollowingState.MutuallyFollowing -> {
viewBinding.textViewFollowingState.setText(R.string.mutually_following)
viewBinding.followButton.setText(R.string.unfollow)
viewBinding.followButton.isChecked = true
}
FollowingState.ThisUserIsFollowingMe -> {
viewBinding.textViewFollowingState.setText(R.string.following_you)
viewBinding.followButton.setText(R.string.follow)
viewBinding.followButton.isChecked = false
}
FollowingState.NotMutuallyFollowing -> {
viewBinding.textViewFollowingState.text = ""
viewBinding.followButton.setText(R.string.follow)
viewBinding.followButton.isChecked = false
}
}
}
@ -128,6 +141,10 @@ class ProfileMainFragment : Fragment() {
}
}
viewBinding.goToFollowersBtn.setOnClickListener {
findNavController().navigate(ProfileMainFragmentDirections.actionDiscussionsFragmentToMainFollowersFragment())
}
viewBinding.feedRecyclerView.adapter = postsAdapter
viewBinding.feedRecyclerView.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
@ -191,7 +208,7 @@ class ProfileMainFragment : Fragment() {
}
override fun onOptions(postId: Long) {
optionsViewModel.setOptions(Options.postOptions, FeedFragment.CALLER_ID)
optionsViewModel.setOptions(Options.myPostOptions, FeedFragment.CALLER_ID)
val modalBottomSheet = BottomSheetPostOptionsFragment()
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
}

View File

@ -33,6 +33,18 @@
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/text_view_following_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textAlignment="center"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Following this profile" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
@ -42,7 +54,7 @@
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"
tools:text="Erik Cavazos" />
<TextView
@ -57,17 +69,16 @@
app:layout_constraintEnd_toEndOf="parent"
tools:text="Hi there, I am software developer!" />
<TextView
android:id="@+id/text_view_following_state"
<com.google.android.material.button.MaterialButton
android:id="@+id/go_to_followers_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:textAlignment="center"
android:textStyle="bold"
app:layout_constraintTop_toBottomOf="@id/text_view_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Following this profile" />
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
style="@style/Widget.Material3.Button.TextButton"
app:layout_constraintTop_toBottomOf="@id/text_view_description"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/follow_button"
@ -75,11 +86,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:checkable="true"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state" />
app:layout_constraintTop_toBottomOf="@id/go_to_followers_btn" />

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.appbar.MaterialToolbar
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout_followers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|snap"/>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager_followers_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -49,6 +49,6 @@
android:label="UserLinkFragment" />
<fragment
android:id="@+id/mainFollowersFragment"
android:name="com.isolaatti.profile.ui.MainFollowersFragment"
android:name="com.isolaatti.followers.ui.MainFollowersFragment"
android:label="MainFollowersFragment" />
</navigation>

View File

@ -51,6 +51,7 @@
<string name="report_profile">Report profile</string>
<string name="block_profile">Block profile</string>
<string name="sort">Sort</string>
<string name="followers">Followers</string>
<string name="followings">Following</string>
<string name="following_user">Following</string>
@ -59,4 +60,7 @@
<string name="user_link">User link</string>
<string name="follow">Follow</string>
<string name="unfollow">Unfollow</string>
<string name="go_to_followers_btn_text">Followers: %s Following: %s</string>
<string name="thousand_suffix">K</string>
<string name="million_suffix">M</string>
</resources>