Start of profile tabs

This commit is contained in:
Marie 2022-10-17 22:32:14 +02:00 committed by Matthieu
parent e1f7018b19
commit 35948439e9
6 changed files with 195 additions and 68 deletions

View File

@ -10,6 +10,7 @@ import android.widget.ImageView
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@ -18,9 +19,13 @@ import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.pixeldroid.app.R import org.pixeldroid.app.R
@ -37,6 +42,7 @@ import org.pixeldroid.app.utils.*
import org.pixeldroid.app.utils.api.PixelfedAPI import org.pixeldroid.app.utils.api.PixelfedAPI
import org.pixeldroid.app.utils.api.objects.Account import org.pixeldroid.app.utils.api.objects.Account
import org.pixeldroid.app.utils.api.objects.Attachment import org.pixeldroid.app.utils.api.objects.Attachment
import org.pixeldroid.app.utils.api.objects.Results
import org.pixeldroid.app.utils.api.objects.Status import org.pixeldroid.app.utils.api.objects.Status
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
import retrofit2.HttpException import retrofit2.HttpException
@ -47,11 +53,9 @@ class ProfileActivity : BaseThemedWithBarActivity() {
private lateinit var domain : String private lateinit var domain : String
private lateinit var accountId : String private lateinit var accountId : String
private lateinit var binding: ActivityProfileBinding private lateinit var binding: ActivityProfileBinding
private lateinit var profileAdapter: PagingDataAdapter<Status, RecyclerView.ViewHolder>
private lateinit var viewModel: FeedViewModel<Status> private lateinit var viewModel: FeedViewModel<Status>
private var user: UserDatabaseEntity? = null private var user: UserDatabaseEntity? = null
private var job: Job? = null
@OptIn(ExperimentalPagingApi::class) @OptIn(ExperimentalPagingApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@ -79,36 +83,60 @@ class ProfileActivity : BaseThemedWithBarActivity() {
) )
)[FeedViewModel::class.java] as FeedViewModel<Status> )[FeedViewModel::class.java] as FeedViewModel<Status>
profileAdapter = ProfilePostsAdapter() val tabs = createSearchTabs(account)
initAdapter(binding.profileProgressBar, binding.profileRefreshLayout, setupTabs(tabs)
binding.profilePostsRecyclerView, binding.motionLayout, binding.errorLayout,
profileAdapter)
binding.profilePostsRecyclerView.layoutManager = GridLayoutManager(this, 3)
binding.profileRefreshLayout.setOnRefreshListener {
setContent(account)
profileAdapter.refresh()
}
setContent(account) setContent(account)
job = launch(job, lifecycleScope, viewModel, profileAdapter)
} }
/** private fun createSearchTabs(account: Account?): Array<Fragment>{
* Shows or hides the error in the profile
*/ val profileGridFragment = ProfileFeedFragment()
private fun showError(errorText: String = getString(R.string.profile_error), show: Boolean = true){ val profileFeedFragment = ProfileFeedFragment()
if(show){ val profileBookmarksFragment = ProfileFeedFragment() // TODO: bookmark fragment
binding.profileProgressBar.visibility = View.GONE val arguments = Bundle()
binding.motionLayout.transitionToEnd() arguments.putSerializable(Account.ACCOUNT_TAG, account)
binding.errorLayout.errorText.text = errorText profileGridFragment.arguments = arguments
} else if(binding.motionLayout.progress == 1F) { profileFeedFragment.arguments = arguments
binding.motionLayout.transitionToStart() profileBookmarksFragment.arguments = arguments
} return arrayOf(
binding.profileRefreshLayout.isRefreshing = false profileGridFragment,
profileFeedFragment,
profileBookmarksFragment
)
} }
private fun setupTabs(
tabs: Array<Fragment>
){
binding.viewPager.adapter = object : FragmentStateAdapter(this) {
override fun createFragment(position: Int): Fragment {
return tabs[position]
}
override fun getItemCount(): Int {
return 3
}
}
TabLayoutMediator(binding.profileTabs, binding.viewPager) { tab, position ->
tab.tabLabelVisibility = TabLayout.TAB_LABEL_VISIBILITY_UNLABELED
when (position) {
0 -> {
tab.setText("Grid view")
tab.setIcon(R.drawable.grid_on_black_24dp)
}
1 -> {
tab.setText("Feed view")
tab.setIcon(R.drawable.feed_view)
}
2 -> {
tab.setText("Bookmarks")
tab.setIcon(R.drawable.bookmark)
}
}
}.attach()
}
private fun setContent(account: Account?) { private fun setContent(account: Account?) {
if(account != null) { if(account != null) {
setViews(account) setViews(account)
@ -120,9 +148,17 @@ class ProfileActivity : BaseThemedWithBarActivity() {
api.verifyCredentials() api.verifyCredentials()
} catch (exception: IOException) { } catch (exception: IOException) {
Log.e("ProfileActivity:", exception.toString()) Log.e("ProfileActivity:", exception.toString())
return@launchWhenResumed showError() Toast.makeText(
applicationContext, "Could not get your profile",
Toast.LENGTH_SHORT
).show()
return@launchWhenResumed
} catch (exception: HttpException) { } catch (exception: HttpException) {
return@launchWhenResumed showError() Toast.makeText(
applicationContext, "Could not get your profile",
Toast.LENGTH_SHORT
).show()
return@launchWhenResumed
} }
setViews(myAccount) setViews(myAccount)
} }

View File

@ -0,0 +1,58 @@
package org.pixeldroid.app.profile
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import androidx.paging.ExperimentalPagingApi
import org.pixeldroid.app.posts.feeds.uncachedFeeds.*
import org.pixeldroid.app.posts.feeds.uncachedFeeds.profile.ProfileContentRepository
import org.pixeldroid.app.utils.api.objects.Account
import org.pixeldroid.app.utils.api.objects.Status
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
/**
* Fragment to show a list of [Account]s, as a result of a search.
*/
class ProfileFeedFragment : UncachedFeedFragment<Status>() {
private lateinit var accountId : String
private var user: UserDatabaseEntity? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
adapter = ProfilePostsAdapter()
//get the currently active user
user = db.userDao().getActiveUser()
// Set profile according to given account
val account = arguments?.getSerializable(Account.ACCOUNT_TAG) as Account?
accountId = account?.id ?: user!!.user_id
}
@OptIn(ExperimentalPagingApi::class)
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = super.onCreateView(inflater, container, savedInstanceState)
// Get the view model
@Suppress("UNCHECKED_CAST")
viewModel = ViewModelProvider(requireActivity(), ProfileViewModelFactory(
ProfileContentRepository(
apiHolder.setToCurrentUser(),
accountId
)
)
)["Profile", FeedViewModel::class.java] as FeedViewModel<Status>
launch()
initSearch()
return view
}
}

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M2,21h19v-3H2v3zM20,8H3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1V9c0,-0.55 -0.45,-1 -1,-1zM2,3v3h19V3H2z"/>
</vector>

View File

@ -46,7 +46,6 @@
android:gravity="center" android:gravity="center"
android:text="@string/default_nposts" android:text="@string/default_nposts"
android:textStyle="bold" android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/descriptionTextView" /> app:layout_constraintTop_toBottomOf="@+id/descriptionTextView" />
@ -89,7 +88,6 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/profilePictureImageView" /> app:layout_constraintTop_toBottomOf="@id/profilePictureImageView" />
<TextView <TextView
android:id="@+id/descriptionTextView" android:id="@+id/descriptionTextView"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -123,49 +121,26 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/profilePictureImageView" app:layout_constraintStart_toEndOf="@+id/profilePictureImageView"
app:layout_constraintTop_toTopOf="@+id/profilePictureImageView" /> app:layout_constraintTop_toTopOf="@+id/profilePictureImageView" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/profileTabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/nbPostsTextView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<ProgressBar
android:id="@+id/profileProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout <androidx.viewpager2.widget.ViewPager2
android:id="@+id/profileRefreshLayout" android:id="@+id/view_pager"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:visibility="visible"
app:layoutDescription="@xml/error_layout_xml_error_scene">
<include
android:id="@+id/errorLayout"
layout="@layout/error_layout"
tools:layout_editor_absoluteX="50dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/profilePostsRecyclerView"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/errorLayout"
tools:listitem="@layout/fragment_profile_posts" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<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"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/profileProgressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="16dp" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/profileRefreshLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motionLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:visibility="visible"
app:layoutDescription="@xml/error_layout_xml_error_scene">
<include
android:id="@+id/errorLayout"
layout="@layout/error_layout"
tools:layout_editor_absoluteX="50dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/profilePostsRecyclerView"
android:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layoutManager="LinearLayoutManager"
app:layout_constraintTop_toBottomOf="@id/errorLayout"
tools:listitem="@layout/fragment_profile_posts" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>