diff --git a/app/src/main/java/org/pixeldroid/app/posts/AlbumActivity.kt b/app/src/main/java/org/pixeldroid/app/posts/AlbumActivity.kt index eb5982a2..6b64da81 100644 --- a/app/src/main/java/org/pixeldroid/app/posts/AlbumActivity.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/AlbumActivity.kt @@ -3,40 +3,99 @@ package org.pixeldroid.app.posts import android.os.Bundle import android.view.MenuItem import android.view.View +import androidx.activity.viewModels 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.utils.api.objects.Attachment class AlbumActivity : AppCompatActivity() { + private val model: AlbumViewModel by viewModels() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val binding = ActivityAlbumBinding.inflate(layoutInflater) + val binding = ActivityAlbumBinding.inflate(layoutInflater) setContentView(binding.root) - val mediaAttachments = intent.getSerializableExtra("images") as ArrayList - val index = intent.getIntExtra("index", 0) - binding.albumPager.adapter = AlbumViewPagerAdapter(mediaAttachments, + + binding.albumPager.adapter = AlbumViewPagerAdapter( + model.uiState.value.mediaAttachments, sensitive = false, opened = true, //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 - } - else if((mediaAttachments.size) > 1) { + } else if ((model.uiState.value.mediaAttachments.size) > 1) { binding.postIndicator.setViewPager(binding.albumPager) binding.postIndicator.visibility = View.VISIBLE } else { 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?.setDisplayShowTitleEnabled(false) 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 { diff --git a/app/src/main/java/org/pixeldroid/app/posts/AlbumViewModel.kt b/app/src/main/java/org/pixeldroid/app/posts/AlbumViewModel.kt new file mode 100644 index 00000000..de1d7d0a --- /dev/null +++ b/app/src/main/java/org/pixeldroid/app/posts/AlbumViewModel.kt @@ -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 = 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 + private val _isActionBarHidden: MutableStateFlow + + init { + _uiState = MutableStateFlow(AlbumUiState( + mediaAttachments = state[ALBUM_IMAGES] ?: ArrayList(), + index = state[ALBUM_INDEX] ?: 0 + )) + _isActionBarHidden = MutableStateFlow(false) + } + + val uiState: StateFlow = _uiState.asStateFlow() + val isActionBarHidden: StateFlow = _isActionBarHidden + + fun barHide() { + _isActionBarHidden.update { !it } + } + + fun positionSelected(position: Int) { + _uiState.update { it.copy(index = position) } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt b/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt index d0c16c5b..ea1fee78 100644 --- a/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/NestedScrollableHost.kt @@ -88,8 +88,8 @@ class NestedScrollableHost(context: Context, attrs: AttributeSet? = null) : } val intent = Intent(context, AlbumActivity::class.java) - intent.putExtra("images", images) - intent.putExtra("index", (child as ViewPager2).currentItem) + intent.putExtra(AlbumViewModel.ALBUM_IMAGES, images) + intent.putExtra(AlbumViewModel.ALBUM_INDEX, (child as ViewPager2).currentItem) context.startActivity(intent) diff --git a/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt b/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt index 9a7d5b9f..8fa7fbba 100644 --- a/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt +++ b/app/src/main/java/org/pixeldroid/app/posts/StatusViewHolder.kt @@ -1,7 +1,6 @@ package org.pixeldroid.app.posts import android.annotation.SuppressLint -import android.app.Activity import android.content.Intent import android.content.pm.PackageManager.PERMISSION_DENIED import android.graphics.Typeface @@ -18,11 +17,7 @@ import android.view.View import android.view.ViewGroup import android.widget.* import androidx.activity.result.ActivityResultLauncher -import androidx.appcompat.app.AppCompatActivity 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.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView @@ -806,17 +801,15 @@ class StatusViewHolder(val binding: PostFragmentBinding) : RecyclerView.ViewHold class AlbumViewPagerAdapter( private val media_attachments: List, private var sensitive: Boolean?, private val opened: Boolean, private val alwaysShowNsfw: Boolean, -) : - RecyclerView.Adapter() { - - private var isActionBarHidden: Boolean = false + private val clickCallback: (() -> Unit)? = null +) : RecyclerView.Adapter() { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { return if(!opened) ViewHolderClosed(AlbumImageViewBinding.inflate( LayoutInflater.from(parent.context), parent, false )) else ViewHolderOpen(OpenedAlbumBinding.inflate( LayoutInflater.from(parent.context), parent, false - )) + ), clickCallback!!) } override fun getItemCount() = media_attachments.size @@ -847,24 +840,6 @@ class AlbumViewPagerAdapter( setDoubleTapZoomDpi(240) 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) .asDrawable().fitCenter() @@ -910,9 +885,13 @@ class AlbumViewPagerAdapter( 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 videoPlayButton: ImageView = binding.videoPlayButton + + init { + image.setOnClickListener { clickCallback() } + } } class ViewHolderClosed(override val binding: AlbumImageViewBinding) : ViewHolder(binding) { override val image: ImageView = binding.imageImageView