Refactor control view to the template's GalleryFragment

If this works out, it will eventually be renamed appropriately
This commit is contained in:
Luke Hubmayer-Werner 2024-08-27 15:22:08 +09:30
parent f24522d728
commit 9ae2b36a3c
5 changed files with 177 additions and 154 deletions

View File

@ -13,6 +13,7 @@ import android.view.WindowManager
import android.widget.ImageView
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.navigation.NavigationView
import androidx.navigation.findNavController
@ -26,6 +27,7 @@ import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import com.google.android.material.chip.Chip
import com.lhw.pdf.databinding.ActivityMainBinding
import com.lhw.pdf.ui.gallery.GalleryViewModel
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import java.io.File
import java.io.FileOutputStream
@ -34,6 +36,7 @@ import kotlin.math.max
import kotlin.math.min
class MainActivity : AppCompatActivity() {
private val viewModel: GalleryViewModel by viewModels()
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainBinding
private lateinit var displayManager: DisplayManager
@ -46,7 +49,6 @@ class MainActivity : AppCompatActivity() {
private val presentations = mutableMapOf<Int, MyPresentation>()
private lateinit var pdfDocument: PdfDocument
private val showPages = mutableListOf<Boolean>()
private val thumbnailImageViews = mutableListOf<ImageView>()
private val defaultCachedFileName = "cached.pdf"
private fun setPagesPerLandscape(pages: Float) {
@ -118,35 +120,7 @@ class MainActivity : AppCompatActivity() {
presentation.show()
}
private fun reLayoutThumbnails() {
val container = binding.appBarMain.contentMain.thumbnailsLayout
val disabledContainer = binding.appBarMain.contentMain.thumbnailsDisabledLayout
container.removeAllViewsInLayout()
disabledContainer.removeAllViewsInLayout()
showPages.map { if (it) container else disabledContainer }.zip(thumbnailImageViews).forEach { (cont, img) ->
cont.addView(img)
}
updatePresentations(false)
}
private fun populateThumbnails() {
showPages.clear()
for ((index, bitmap) in pdfDocument.bitmapThumbnails) {
val img = ImageView(this)
img.setImageBitmap(bitmap)
img.setOnClickListener {
showPages[index] = !showPages[index]
//img.setColorFilter(if (showPages[index]) 0 else 0x7F000000, PorterDuff.Mode.DARKEN)
reLayoutThumbnails()
}
thumbnailImageViews.add(img)
showPages.add(true)
}
reLayoutThumbnails()
}
private fun updateDisplayText() {
val displayText = binding.appBarMain.contentMain.textDisplays
val text = StringBuilder()
displayManager.displays.forEach {
@ -159,7 +133,7 @@ class MainActivity : AppCompatActivity() {
text.append("\n")
}
text.append(presentations)
displayText.text = text.toString()
viewModel.textDisplays.value = text.toString()
}
override fun onSaveInstanceState(outState: Bundle) {
@ -180,6 +154,11 @@ class MainActivity : AppCompatActivity() {
//val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
//windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()) //Doesn't seem to actually fill the vacant space by default
savedInstanceState?.getFloat("thumbnailScrollProgress")?.let { viewModel.thumbnailScrollProgress.value = it }
savedInstanceState?.getFloat("pagesPerLandscape")?.let { pagesPerLandscape = it }
renderAutoCrop = savedInstanceState?.getBoolean("renderAutoCrop") ?: true
val lastFileName = savedInstanceState?.getString("fileName") // TODO: proper filenames
PDFBoxResourceLoader.init(this)
binding = ActivityMainBinding.inflate(layoutInflater)
@ -190,7 +169,6 @@ class MainActivity : AppCompatActivity() {
setSupportActionBar(binding.appBarMain.toolbar)
// Load previous pdf, or included test pdf first
val lastFileName = savedInstanceState?.getString("fileName") // TODO: proper filenames
var file = File(cacheDir, defaultCachedFileName)
if (!file.exists()) {
file = inputStreamToCache(defaultCachedFileName, resources.openRawResource(R.raw.testpdf))
@ -199,45 +177,40 @@ class MainActivity : AppCompatActivity() {
// Then overwrite it with any pdf sent via intent
handleIntent(intent)
renderAutoCrop = savedInstanceState?.getBoolean("renderAutoCrop") ?: true
pdfDocument.renderThumbnails(thumbnailWidth, thumbnailHeight)
displayManager.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION).forEach(::makePresentationView)
populateThumbnails() // Populates showPages
val bitmaps = pdfDocument.bitmapThumbnails.toSortedMap().values.toList()
showPages.clear()
bitmaps.forEach { _ -> showPages.add(true) }
savedInstanceState?.getBooleanArray("showPages")?.forEachIndexed { i, show ->
showPages[i] = show
}
reLayoutThumbnails()
viewModel.showPages.value = showPages.toList()
viewModel.pageThumbnails.value = bitmaps
val container = binding.appBarMain.contentMain.thumbnailsLayout
val containerScroll = binding.appBarMain.contentMain.thumbnailsScroll
containerScroll.viewTreeObserver.addOnScrollChangedListener {
thumbnailScrollProgress = containerScroll.scrollX.toFloat() / (container.width - containerScroll.width)
presentations.values.forEach {it.setScrollProgress(thumbnailScrollProgress)}
}
savedInstanceState?.getFloat("thumbnailScrollProgress")?.let { thumbnailScrollProgress = it }
containerScroll.scrollTo((thumbnailScrollProgress * (container.width - containerScroll.width)).toInt(), 0)
savedInstanceState?.getFloat("pagesPerLandscape")?.let { pagesPerLandscape = it }
val pageZoomLevels = arrayOf(1F, 1.5F, 2F, 2.5F, 3F, 3.5F, 4F, 5F, 6F, 8F, 10F)
val chipGroupPages = binding.appBarMain.contentMain.chipGroupPages
pageZoomLevels.forEach { pages ->
val chip = Chip(this)
chip.text = "$pages pages"
chip.isCheckable = true
chip.isChecked = (pages == pagesPerLandscape)
chip.setOnCheckedChangeListener { _, checked -> if (checked) setPagesPerLandscape(pages) }
chipGroupPages.addView(chip)
viewModel.pagesPerLandscape.observe(this) {
setPagesPerLandscape(it)
}
binding.appBarMain.contentMain.chipAutoCrop.setOnCheckedChangeListener { _, checked ->
renderAutoCrop = checked
viewModel.renderAutoCrop.observe(this) {
renderAutoCrop = it
updatePresentations()
}
binding.appBarMain.contentMain.chipUsePdfBox.setOnCheckedChangeListener { _, checked ->
usePdfBox = checked
viewModel.usePdfBox.observe(this) {
usePdfBox = it
pdfDocument.usePdfBox = usePdfBox
updatePresentations()
}
viewModel.showPages.observe(this) {
it.forEachIndexed() {i, shown -> showPages[i] = shown}
updatePresentations(false)
}
viewModel.thumbnailScrollProgress.observe(this) { thumbnailScrollProgress ->
presentations.values.forEach {it.setScrollProgress(thumbnailScrollProgress)}
}
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main)

View File

@ -1,36 +1,70 @@
package com.lhw.pdf.ui.gallery
import android.graphics.Bitmap
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.chip.Chip
import com.lhw.pdf.databinding.FragmentGalleryBinding
class GalleryFragment : Fragment() {
private val galleryViewModel: GalleryViewModel by activityViewModels()
private var _binding: FragmentGalleryBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private val pageZoomLevels = arrayOf(1F, 1.5F, 2F, 2.5F, 3F, 3.5F, 4F, 5F, 6F, 8F, 10F)
private val pageZoomLevelChips = mutableMapOf<Float, Chip>()
private val thumbnailImageViews = mutableListOf<ImageView>()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val galleryViewModel =
ViewModelProvider(this)[GalleryViewModel::class.java]
// val galleryViewModel = ViewModelProvider(this)[GalleryViewModel::class.java]
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView: TextView = binding.textGallery
galleryViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
val chipGroupPages = binding.chipGroupPages
pageZoomLevels.forEach { pages ->
val chip = Chip(context)
chip.text = "$pages pages"
chip.isCheckable = true
chip.setOnCheckedChangeListener { _, checked -> if (checked) galleryViewModel.pagesPerLandscape.value = pages }
chipGroupPages.addView(chip)
pageZoomLevelChips[pages] = chip
}
pageZoomLevelChips[galleryViewModel.pagesPerLandscape.value]?.isChecked = true
binding.chipAutoCrop.isChecked = galleryViewModel.renderAutoCrop.value!!
binding.chipUsePdfBox.isChecked = galleryViewModel.usePdfBox.value!!
galleryViewModel.textDisplays.observe(viewLifecycleOwner) { binding.textDisplays.text = it }
galleryViewModel.usePdfBox.observe(viewLifecycleOwner) { binding.chipUsePdfBox.isChecked = it }
galleryViewModel.renderAutoCrop.observe(viewLifecycleOwner) { binding.chipAutoCrop.isChecked = it }
galleryViewModel.pagesPerLandscape.observe(viewLifecycleOwner) {
pageZoomLevelChips[it]?.isChecked = true
}
binding.chipAutoCrop.setOnCheckedChangeListener { _, checked -> galleryViewModel.renderAutoCrop.value = checked }
binding.chipUsePdfBox.setOnCheckedChangeListener { _, checked -> galleryViewModel.usePdfBox.value = checked }
galleryViewModel.pageThumbnails.observe(viewLifecycleOwner, ::populateThumbnails)
val container = binding.thumbnailsLayout
val containerScroll = binding.thumbnailsScroll
containerScroll.scrollTo(((galleryViewModel.thumbnailScrollProgress.value ?: 0F) * (container.width - containerScroll.width)).toInt(), 0)
containerScroll.viewTreeObserver.addOnScrollChangedListener {
galleryViewModel.thumbnailScrollProgress.value = containerScroll.scrollX.toFloat() / (container.width - containerScroll.width)
}
return root
}
@ -39,4 +73,31 @@ class GalleryFragment : Fragment() {
super.onDestroyView()
_binding = null
}
private fun reLayoutThumbnails() {
val container = binding.thumbnailsLayout
val disabledContainer = binding.thumbnailsDisabledLayout
container.removeAllViewsInLayout()
disabledContainer.removeAllViewsInLayout()
galleryViewModel.showPages.value
?.map { if (it) container else disabledContainer }
?.zip(thumbnailImageViews)?.forEach { (cont, img) ->
cont.addView(img)
}
}
private fun populateThumbnails(bitmaps: List<Bitmap>) {
bitmaps.forEachIndexed() { index, bitmap ->
val img = ImageView(context)
img.setImageBitmap(bitmap)
img.setOnClickListener {
val showPages = galleryViewModel.showPages.value!!.toMutableList()
showPages[index] = !showPages[index]
galleryViewModel.showPages.value = showPages.toList()
reLayoutThumbnails()
}
thumbnailImageViews.add(img)
}
reLayoutThumbnails()
}
}

View File

@ -1,13 +1,16 @@
package com.lhw.pdf.ui.gallery
import android.graphics.Bitmap
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class GalleryViewModel : ViewModel() {
private val _text = MutableLiveData<String>().apply {
value = "This is gallery Fragment"
}
val text: LiveData<String> = _text
val pageThumbnails = MutableLiveData<List<Bitmap>>().apply { value = listOf() }
val showPages = MutableLiveData<List<Boolean>>().apply { value = listOf() }
val thumbnailScrollProgress = MutableLiveData<Float>().apply { value = 0F }
val textDisplays = MutableLiveData<String>().apply { value = "" }
val pagesPerLandscape = MutableLiveData<Float>().apply { value = 3F }
val renderAutoCrop = MutableLiveData<Boolean>().apply { value = true }
val usePdfBox = MutableLiveData<Boolean>().apply { value = false }
}

View File

@ -18,79 +18,4 @@
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/mobile_navigation" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:id="@+id/thumbnails_disabled_scroll"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#80C01010">
<LinearLayout
android:id="@+id/thumbnails_disabled_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:showIn="@layout/content_main" />
</HorizontalScrollView>
<HorizontalScrollView
android:id="@+id/thumbnails_scroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3">
<LinearLayout
android:id="@+id/thumbnails_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:showIn="@layout/content_main" />
</HorizontalScrollView>
<TextView
android:id="@+id/text_displays"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_pages"
app:singleSelection="true"
app:selectionRequired="true"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</com.google.android.material.chip.ChipGroup>
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_toggles"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.material.chip.Chip
android:id="@+id/chip_auto_crop"
android:checkable="true"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Auto Crop" />
<com.google.android.material.chip.Chip
android:id="@+id/chip_use_pdf_box"
android:checkable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Use PdfBox renderer (slower)" />
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -6,17 +6,78 @@
android:layout_height="match_parent"
tools:context=".ui.gallery.GalleryFragment">
<TextView
android:id="@+id/text_gallery"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:layout_height="match_parent"
android:orientation="vertical">
<HorizontalScrollView
android:id="@+id/thumbnails_disabled_scroll"
android:layout_width="match_parent"
android:layout_height="300dp"
android:background="#80C01010">
<LinearLayout
android:id="@+id/thumbnails_disabled_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:showIn="@layout/content_main" />
</HorizontalScrollView>
<HorizontalScrollView
android:id="@+id/thumbnails_scroll"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3">
<LinearLayout
android:id="@+id/thumbnails_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
tools:showIn="@layout/content_main" />
</HorizontalScrollView>
<TextView
android:id="@+id/text_displays"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_pages"
app:singleSelection="true"
app:selectionRequired="true"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</com.google.android.material.chip.ChipGroup>
<com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_toggles"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<com.google.android.material.chip.Chip
android:id="@+id/chip_auto_crop"
android:checkable="true"
android:checked="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Auto Crop" />
<com.google.android.material.chip.Chip
android:id="@+id/chip_use_pdf_box"
android:checkable="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Use PdfBox renderer (slower)" />
</com.google.android.material.chip.ChipGroup>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>