WIP barra colapsable en pantalla de perfil y trae informacion de perfil
This commit is contained in:
parent
7f6f96a005
commit
b719cce98d
@ -15,6 +15,7 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import androidx.lifecycle.Observer
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.isolaatti.BuildConfig
|
import com.isolaatti.BuildConfig
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
@ -25,6 +26,9 @@ import com.isolaatti.posting.PostViewerActivity
|
|||||||
import com.isolaatti.posting.posts.presentation.PostsViewModel
|
import com.isolaatti.posting.posts.presentation.PostsViewModel
|
||||||
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
import com.isolaatti.posting.comments.presentation.BottomSheetPostComments
|
||||||
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
|
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.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
|
||||||
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
|
||||||
import com.isolaatti.posting.posts.ui.CreatePostActivity
|
import com.isolaatti.posting.posts.ui.CreatePostActivity
|
||||||
@ -45,11 +49,14 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance() = FeedFragment()
|
fun newInstance() = FeedFragment()
|
||||||
|
const val CALLER_ID = 20
|
||||||
}
|
}
|
||||||
|
|
||||||
private val viewModel: PostsViewModel by activityViewModels()
|
private val viewModel: PostsViewModel by activityViewModels()
|
||||||
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
private val errorViewModel: ErrorMessageViewModel by activityViewModels()
|
||||||
private val screenViewModel: FeedViewModel by viewModels()
|
private val screenViewModel: FeedViewModel by viewModels()
|
||||||
|
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
||||||
|
|
||||||
private lateinit var viewBinding: FragmentFeedBinding
|
private lateinit var viewBinding: FragmentFeedBinding
|
||||||
private lateinit var adapter: PostsRecyclerViewAdapter
|
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(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
@ -175,6 +198,8 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
screenViewModel.getProfile()
|
screenViewModel.getProfile()
|
||||||
|
|
||||||
|
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onNewMenuItemClicked(v: View) {
|
fun onNewMenuItemClicked(v: View) {
|
||||||
@ -187,6 +212,7 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
|||||||
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
||||||
|
|
||||||
override fun onOptions(postId: Long) {
|
override fun onOptions(postId: Long) {
|
||||||
|
optionsViewModel.setOptions(Options.postOptions, CALLER_ID)
|
||||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
@ -3,17 +3,40 @@ package com.isolaatti.profile.presentation
|
|||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
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.data.remote.UserProfileDto
|
||||||
import com.isolaatti.profile.domain.ProfileRepository
|
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 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
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@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>()
|
private val _profile = MutableLiveData<UserProfileDto>()
|
||||||
val profile: LiveData<UserProfileDto> get() = _profile
|
val profile: LiveData<UserProfileDto> get() = _profile
|
||||||
|
|
||||||
|
private val _posts = MutableLiveData<FeedDto>()
|
||||||
|
val posts: LiveData<FeedDto> get() = _posts
|
||||||
|
|
||||||
fun getProfile(profileId: Int) {
|
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) {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3,6 +3,7 @@ package com.isolaatti.profile.ui
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import androidx.activity.addCallback
|
import androidx.activity.addCallback
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
@ -13,6 +14,8 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.viewpager.widget.PagerAdapter
|
import androidx.viewpager.widget.PagerAdapter
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
import androidx.viewpager2.adapter.FragmentViewHolder
|
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.google.android.material.tabs.TabLayoutMediator
|
||||||
import com.isolaatti.R
|
import com.isolaatti.R
|
||||||
import com.isolaatti.databinding.ActivityProfileBinding
|
import com.isolaatti.databinding.ActivityProfileBinding
|
||||||
@ -24,35 +27,19 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ProfileActivity : AppCompatActivity() {
|
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
|
lateinit var viewBinding: ActivityProfileBinding
|
||||||
private val viewModel: ProfileViewModel by viewModels()
|
private val viewModel: ProfileViewModel by viewModels()
|
||||||
|
private var userId: Int? = null
|
||||||
|
|
||||||
|
private var title = ""
|
||||||
|
|
||||||
private val profileObserver = Observer<UserProfileDto> { profile ->
|
private val profileObserver = Observer<UserProfileDto> { profile ->
|
||||||
Picasso.get()
|
Picasso.get()
|
||||||
.load(UrlGen.userProfileImage(profile.id))
|
.load(UrlGen.userProfileImage(profile.id))
|
||||||
.into(viewBinding.profileImageView)
|
.into(viewBinding.profileImageView)
|
||||||
|
|
||||||
|
title = profile.name
|
||||||
viewBinding.textViewUsername.text = profile.name
|
viewBinding.textViewUsername.text = profile.name
|
||||||
viewBinding.textViewDescription.text = profile.descriptionText
|
viewBinding.textViewDescription.text = profile.descriptionText
|
||||||
}
|
}
|
||||||
@ -60,27 +47,34 @@ class ProfileActivity : AppCompatActivity() {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
|
viewBinding = ActivityProfileBinding.inflate(layoutInflater)
|
||||||
setContentView(viewBinding.root)
|
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 {
|
viewBinding.topAppBar.setNavigationOnClickListener {
|
||||||
finish()
|
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)
|
viewModel.profile.observe(this, profileObserver)
|
||||||
|
|
||||||
|
userId?.let { viewModel.getProfile(it) }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -9,39 +9,19 @@
|
|||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/topAppBar_layout"
|
android:id="@+id/topAppBar_layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:id="@+id/collapsing_toolbar_layout"
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
|
||||||
android:id="@+id/top_app_bar"
|
|
||||||
style="@style/Theme.Isolaatti"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="410dp"
|
||||||
app:navigationIcon="@drawable/baseline_arrow_back_24"
|
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||||
app:navigationIconTint="@color/on_surface"
|
app:contentScrim="@color/purple">
|
||||||
app:title="Profile"
|
|
||||||
app:titleCentered="true" />
|
|
||||||
|
|
||||||
|
|
||||||
</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
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="350dp"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:layout_marginTop="56dp">
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent">
|
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/profile_image_view"
|
android:id="@+id/profile_image_view"
|
||||||
@ -111,23 +91,30 @@
|
|||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"/>
|
app:layout_constraintTop_toBottomOf="@id/text_view_following_state"/>
|
||||||
|
|
||||||
|
|
||||||
<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.constraintlayout.widget.ConstraintLayout>
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
<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"/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@ -13,4 +13,7 @@
|
|||||||
<item name="cornerSize">50%</item>
|
<item name="cornerSize">50%</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="TransparentText" parent="@android:style/TextAppearance">
|
||||||
|
<item name="android:textColor">#00000000</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
x
Reference in New Issue
Block a user