Merge branch 'view_models' into 'master'

Use ViewModel in AlbumActivity

See merge request pixeldroid/PixelDroid!558
This commit is contained in:
Matthieu 2024-03-10 10:22:07 +00:00
commit 7acd4cface
4 changed files with 125 additions and 41 deletions

View File

@ -3,40 +3,99 @@ package org.pixeldroid.app.posts
import android.os.Bundle import android.os.Bundle
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.viewpager2.widget.ViewPager2
import kotlinx.coroutines.launch
import org.pixeldroid.app.databinding.ActivityAlbumBinding import org.pixeldroid.app.databinding.ActivityAlbumBinding
import org.pixeldroid.app.utils.api.objects.Attachment
class AlbumActivity : AppCompatActivity() { class AlbumActivity : AppCompatActivity() {
private val model: AlbumViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val binding = ActivityAlbumBinding.inflate(layoutInflater)
val binding = ActivityAlbumBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
val mediaAttachments = intent.getSerializableExtra("images") as ArrayList<Attachment>
val index = intent.getIntExtra("index", 0) binding.albumPager.adapter = AlbumViewPagerAdapter(
binding.albumPager.adapter = AlbumViewPagerAdapter(mediaAttachments, model.uiState.value.mediaAttachments,
sensitive = false, sensitive = false,
opened = true, opened = true,
//In the activity, we assume we want to show everything //In the activity, we assume we want to show everything
alwaysShowNsfw = true alwaysShowNsfw = true,
clickCallback = ::clickCallback
) )
binding.albumPager.currentItem = index
if(mediaAttachments.size == 1){ binding.albumPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
override fun onPageSelected(position: Int) { model.positionSelected(position) }
})
if (model.uiState.value.mediaAttachments.size == 1) {
binding.albumPager.isUserInputEnabled = false binding.albumPager.isUserInputEnabled = false
} } else if ((model.uiState.value.mediaAttachments.size) > 1) {
else if((mediaAttachments.size) > 1) {
binding.postIndicator.setViewPager(binding.albumPager) binding.postIndicator.setViewPager(binding.albumPager)
binding.postIndicator.visibility = View.VISIBLE binding.postIndicator.visibility = View.VISIBLE
} else { } else {
binding.postIndicator.visibility = View.GONE binding.postIndicator.visibility = View.GONE
} }
// Not really necessary because the ViewPager saves its state in onSaveInstanceState, but
// it's good to stay consistent in case something gets out of sync
binding.albumPager.setCurrentItem(model.uiState.value.index, false)
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false) supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setBackgroundDrawable(null) supportActionBar?.setBackgroundDrawable(null)
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
model.uiState.collect { uiState ->
binding.albumPager.currentItem = uiState.index
}
}
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
model.isActionBarHidden.collect { isActionBarHidden ->
val windowInsetsController =
WindowCompat.getInsetsController(this@AlbumActivity.window, binding.albumPager)
if (isActionBarHidden) {
// Configure the behavior of the hidden system bars
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
supportActionBar?.hide()
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
binding.postIndicator.visibility = View.GONE
} else {
// Configure the behavior of the hidden system bars
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Show both the status bar and the navigation bar
supportActionBar?.show()
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
if ((model.uiState.value.mediaAttachments.size) > 1) {
binding.postIndicator.visibility = View.VISIBLE
}
}
}
}
}
}
/**
* Callback passed to the AlbumViewPagerAdapter to signal a single click on the image
*/
private fun clickCallback(){
model.barHide()
} }
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {

View File

@ -0,0 +1,46 @@
package org.pixeldroid.app.posts
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import org.pixeldroid.app.utils.api.objects.Attachment
import javax.inject.Inject
data class AlbumUiState(
val mediaAttachments: ArrayList<Attachment> = arrayListOf(),
val index: Int = 0,
)
@HiltViewModel
class AlbumViewModel @Inject constructor(state: SavedStateHandle) : ViewModel() {
companion object {
const val ALBUM_IMAGES = "AlbumViewImages"
const val ALBUM_INDEX = "AlbumViewIndex"
}
private val _uiState: MutableStateFlow<AlbumUiState>
private val _isActionBarHidden: MutableStateFlow<Boolean>
init {
_uiState = MutableStateFlow(AlbumUiState(
mediaAttachments = state[ALBUM_IMAGES] ?: ArrayList(),
index = state[ALBUM_INDEX] ?: 0
))
_isActionBarHidden = MutableStateFlow(false)
}
val uiState: StateFlow<AlbumUiState> = _uiState.asStateFlow()
val isActionBarHidden: StateFlow<Boolean> = _isActionBarHidden
fun barHide() {
_isActionBarHidden.update { !it }
}
fun positionSelected(position: Int) {
_uiState.update { it.copy(index = position) }
}
}

View File

@ -88,8 +88,8 @@ class NestedScrollableHost(context: Context, attrs: AttributeSet? = null) :
} }
val intent = Intent(context, AlbumActivity::class.java) val intent = Intent(context, AlbumActivity::class.java)
intent.putExtra("images", images) intent.putExtra(AlbumViewModel.ALBUM_IMAGES, images)
intent.putExtra("index", (child as ViewPager2).currentItem) intent.putExtra(AlbumViewModel.ALBUM_INDEX, (child as ViewPager2).currentItem)
context.startActivity(intent) context.startActivity(intent)

View File

@ -1,7 +1,6 @@
package org.pixeldroid.app.posts package org.pixeldroid.app.posts
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager.PERMISSION_DENIED import android.content.pm.PackageManager.PERMISSION_DENIED
import android.graphics.Typeface import android.graphics.Typeface
@ -18,11 +17,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.* import android.widget.*
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.lifecycle.LifecycleCoroutineScope import androidx.lifecycle.LifecycleCoroutineScope
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -806,17 +801,15 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold
class AlbumViewPagerAdapter( class AlbumViewPagerAdapter(
private val media_attachments: List<Attachment>, private var sensitive: Boolean?, private val media_attachments: List<Attachment>, private var sensitive: Boolean?,
private val opened: Boolean, private val alwaysShowNsfw: Boolean, private val opened: Boolean, private val alwaysShowNsfw: Boolean,
) : private val clickCallback: (() -> Unit)? = null
RecyclerView.Adapter<AlbumViewPagerAdapter.ViewHolder>() { ) : RecyclerView.Adapter<AlbumViewPagerAdapter.ViewHolder>() {
private var isActionBarHidden: Boolean = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return if(!opened) ViewHolderClosed(AlbumImageViewBinding.inflate( return if(!opened) ViewHolderClosed(AlbumImageViewBinding.inflate(
LayoutInflater.from(parent.context), parent, false LayoutInflater.from(parent.context), parent, false
)) else ViewHolderOpen(OpenedAlbumBinding.inflate( )) else ViewHolderOpen(OpenedAlbumBinding.inflate(
LayoutInflater.from(parent.context), parent, false LayoutInflater.from(parent.context), parent, false
)) ), clickCallback!!)
} }
override fun getItemCount() = media_attachments.size override fun getItemCount() = media_attachments.size
@ -847,24 +840,6 @@ class AlbumViewPagerAdapter(
setDoubleTapZoomDpi(240) setDoubleTapZoomDpi(240)
resetScaleAndCenter() resetScaleAndCenter()
} }
holder.image.setOnClickListener {
val windowInsetsController = WindowCompat.getInsetsController((it.context as Activity).window, it)
// Configure the behavior of the hidden system bars
if (isActionBarHidden) {
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
(it.context as AppCompatActivity).supportActionBar?.show()
windowInsetsController.show(WindowInsetsCompat.Type.systemBars())
isActionBarHidden = false
} else {
// Configure the behavior of the hidden system bars
windowInsetsController.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide both the status bar and the navigation bar
(it.context as AppCompatActivity).supportActionBar?.hide()
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
isActionBarHidden = true
}
}
} }
else Glide.with(holder.binding.root) else Glide.with(holder.binding.root)
.asDrawable().fitCenter() .asDrawable().fitCenter()
@ -910,9 +885,13 @@ class AlbumViewPagerAdapter(
abstract val videoPlayButton: ImageView abstract val videoPlayButton: ImageView
} }
class ViewHolderOpen(override val binding: OpenedAlbumBinding) : ViewHolder(binding) { class ViewHolderOpen(override val binding: OpenedAlbumBinding, clickCallback: () -> Unit) : ViewHolder(binding) {
override val image: SubsamplingScaleImageView = binding.imageImageView override val image: SubsamplingScaleImageView = binding.imageImageView
override val videoPlayButton: ImageView = binding.videoPlayButton override val videoPlayButton: ImageView = binding.videoPlayButton
init {
image.setOnClickListener { clickCallback() }
}
} }
class ViewHolderClosed(override val binding: AlbumImageViewBinding) : ViewHolder(binding) { class ViewHolderClosed(override val binding: AlbumImageViewBinding) : ViewHolder(binding) {
override val image: ImageView = binding.imageImageView override val image: ImageView = binding.imageImageView