WIP barra colapsable en pantalla de perfil y trae informacion de perfil

This commit is contained in:
Erik Cavazos 2023-07-29 00:55:07 -06:00
parent 7f6f96a005
commit b719cce98d
6 changed files with 197 additions and 151 deletions

View File

@ -15,6 +15,7 @@ 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
import com.isolaatti.R
@ -25,6 +26,9 @@ import com.isolaatti.posting.PostViewerActivity
import com.isolaatti.posting.posts.presentation.PostsViewModel
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
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.ui.CreatePostActivity
@ -45,11 +49,14 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
companion object {
fun newInstance() = FeedFragment()
const val CALLER_ID = 20
}
private val viewModel: PostsViewModel by activityViewModels()
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
private val screenViewModel: FeedViewModel by viewModels()
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
private lateinit var viewBinding: FragmentFeedBinding
private lateinit var adapter: PostsRecyclerViewAdapter
@ -59,6 +66,22 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
}
}
val optionsObserver: Observer<OptionClicked> = Observer {
if(it.callerId == CALLER_ID) {
when(it.optionId) {
Options.Option.OPTION_DELETE -> {
}
Options.Option.OPTION_EDIT -> {
}
Options.Option.OPTION_REPORT -> {
}
}
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@ -175,6 +198,8 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
}
}
screenViewModel.getProfile()
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
}
fun onNewMenuItemClicked(v: View) {
@ -187,6 +212,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
override fun onOptions(postId: Long) {
optionsViewModel.setOptions(Options.postOptions, CALLER_ID)
val modalBottomSheet = BottomSheetPostOptionsFragment()
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
}

View File

@ -0,0 +1,13 @@
package com.isolaatti.profile.domain.use_case
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
import com.isolaatti.posting.posts.domain.PostsRepository
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class GetProfilePosts @Inject constructor(private val postsRepository: PostsRepository) {
operator fun invoke(userId: Int, lastId: Long, olderFirst: Boolean, filter: FeedFilterDto): Flow<Resource<FeedDto>> =
postsRepository.getProfilePosts(userId, lastId, olderFirst, filter)
}

View File

@ -3,17 +3,40 @@ package com.isolaatti.profile.presentation
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.profile.data.remote.UserProfileDto
import com.isolaatti.profile.domain.ProfileRepository
import com.isolaatti.profile.domain.use_case.GetProfile
import com.isolaatti.profile.domain.use_case.GetProfilePosts
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ProfileViewModel @Inject constructor(private val profileRepository: ProfileRepository) : ViewModel() {
class ProfileViewModel @Inject constructor(private val getProfileUseCase: GetProfile, private val getProfilePosts: GetProfilePosts) : ViewModel() {
private val _profile = MutableLiveData<UserProfileDto>()
val profile: LiveData<UserProfileDto> get() = _profile
private val _posts = MutableLiveData<FeedDto>()
val posts: LiveData<FeedDto> get() = _posts
fun getProfile(profileId: Int) {
viewModelScope.launch {
getProfileUseCase(profileId).onEach {
if(it is Resource.Success) {
_profile.postValue(it.data!!)
}
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
fun getPosts(profileId: Int, refresh: Boolean) {
}
}

View File

@ -3,6 +3,7 @@ package com.isolaatti.profile.ui
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
@ -13,6 +14,8 @@ import androidx.lifecycle.ViewModelProvider
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.adapter.FragmentViewHolder
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener
import com.google.android.material.tabs.TabLayoutMediator
import com.isolaatti.R
import com.isolaatti.databinding.ActivityProfileBinding
@ -24,35 +27,19 @@ import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class ProfileActivity : AppCompatActivity() {
class ViewPagerAdapter(activity: FragmentActivity) : FragmentStateAdapter(activity) {
override fun getItemCount(): Int = 3
override fun createFragment(position: Int): Fragment {
return when(position) {
0 -> {
DiscussionsFragment()
}
1 -> {
AudiosFragment()
}
2 -> {
ImagesFragment()
}
else -> {Fragment()}
}
}
}
lateinit var viewBinding: ActivityProfileBinding
private val viewModel: ProfileViewModel by viewModels()
private var userId: Int? = null
private var title = ""
private val profileObserver = Observer<UserProfileDto> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
.into(viewBinding.profileImageView)
title = profile.name
viewBinding.textViewUsername.text = profile.name
viewBinding.textViewDescription.text = profile.descriptionText
}
@ -60,27 +47,34 @@ class ProfileActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
userId = intent.extras?.getInt(EXTRA_USER_ID)
var scrollRange = -1
var isShow = false
viewBinding.topAppBarLayout.addOnOffsetChangedListener(object: OnOffsetChangedListener {
override fun onOffsetChanged(appBarLayout: AppBarLayout, verticalOffset: Int) {
if (scrollRange == -1) scrollRange = appBarLayout.totalScrollRange
if(scrollRange + verticalOffset == 0) {
viewBinding.collapsingToolbarLayout.title = title
isShow = true
} else if(isShow) {
viewBinding.collapsingToolbarLayout.title = " "
}
}
})
viewBinding.profileViewPager2.adapter = ViewPagerAdapter(this)
viewBinding.topAppBar.setNavigationOnClickListener {
finish()
}
TabLayoutMediator(viewBinding.profileTabLayout, viewBinding.profileViewPager2) {tab, position ->
when(position) {
0 -> {
tab.text = getText(R.string.discussions)
}
1 -> {
tab.text = getText(R.string.audios)
}
2 -> {
tab.text = getText(R.string.images)
}
}
}.attach()
viewModel.profile.observe(this, profileObserver)
userId?.let { viewModel.getProfile(it) }
}
companion object {

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
@ -9,125 +9,112 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/topAppBar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_app_bar"
style="@style/Theme.Isolaatti"
android:layout_height="wrap_content">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"
app:title="Profile"
app:titleCentered="true" />
android:layout_height="410dp"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="@color/purple">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="350dp"
android:orientation="vertical"
android:layout_marginTop="56dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="1"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
tools:text="Erik Cavazos" />
<TextView
android:id="@+id/text_view_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:maxLines="4"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@id/text_view_username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Hi there, I am software developer!" />
<TextView
android:id="@+id/text_view_following_state"
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" />
<com.google.android.material.button.MaterialButton
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@id/profile_options_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state" />
<com.google.android.material.button.MaterialButton
android:id="@+id/profile_options_button"
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:icon="@drawable/baseline_more_horiz_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/top_app_bar"
style="@style/Theme.Isolaatti"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"
app:layout_collapseMode="pin" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/topAppBar_layout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image_view"
android:layout_width="120dp"
android:layout_height="120dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars" />
<TextView
android:id="@+id/text_view_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_weight="1"
android:textSize="20sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_image_view"
tools:text="Erik Cavazos" />
<TextView
android:id="@+id/text_view_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="20dp"
android:maxLines="4"
android:textAlignment="center"
app:layout_constraintTop_toBottomOf="@id/text_view_username"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Hi there, I am software developer!" />
<TextView
android:id="@+id/text_view_following_state"
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" />
<com.google.android.material.button.MaterialButton
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@id/profile_options_button"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state" />
<com.google.android.material.button.MaterialButton
android:id="@+id/profile_options_button"
style="?attr/materialIconButtonFilledTonalStyle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:icon="@drawable/baseline_more_horiz_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/feed_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
<com.google.android.material.tabs.TabLayout
android:id="@+id/profile_tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabContentStart="56dp"
app:tabMode="fixed"
app:layout_constraintTop_toBottomOf="@id/profile_options_button"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/profile_view_pager2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/profile_tab_layout"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -13,4 +13,7 @@
<item name="cornerSize">50%</item>
</style>
<style name="TransparentText" parent="@android:style/TextAppearance">
<item name="android:textColor">#00000000</item>
</style>
</resources>