diff --git a/app/src/main/java/com/lhw/pdf/MainActivity.kt b/app/src/main/java/com/lhw/pdf/MainActivity.kt index 40bcb9d..445e001 100644 --- a/app/src/main/java/com/lhw/pdf/MainActivity.kt +++ b/app/src/main/java/com/lhw/pdf/MainActivity.kt @@ -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() private lateinit var pdfDocument: PdfDocument private val showPages = mutableListOf() - private val thumbnailImageViews = mutableListOf() 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) diff --git a/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryFragment.kt b/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryFragment.kt index 365474c..32ac285 100644 --- a/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryFragment.kt +++ b/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryFragment.kt @@ -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() + private val thumbnailImageViews = mutableListOf() + 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) { + 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() + } } \ No newline at end of file diff --git a/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryViewModel.kt b/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryViewModel.kt index 2cb5d80..fb46b90 100644 --- a/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryViewModel.kt +++ b/app/src/main/java/com/lhw/pdf/ui/gallery/GalleryViewModel.kt @@ -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().apply { - value = "This is gallery Fragment" - } - val text: LiveData = _text + val pageThumbnails = MutableLiveData>().apply { value = listOf() } + val showPages = MutableLiveData>().apply { value = listOf() } + val thumbnailScrollProgress = MutableLiveData().apply { value = 0F } + val textDisplays = MutableLiveData().apply { value = "" } + val pagesPerLandscape = MutableLiveData().apply { value = 3F } + val renderAutoCrop = MutableLiveData().apply { value = true } + val usePdfBox = MutableLiveData().apply { value = false } } \ No newline at end of file diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 6b9201b..e557d03 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -18,79 +18,4 @@ app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/mobile_navigation" /> - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_gallery.xml b/app/src/main/res/layout/fragment_gallery.xml index 643fe25..bce669c 100644 --- a/app/src/main/res/layout/fragment_gallery.xml +++ b/app/src/main/res/layout/fragment_gallery.xml @@ -6,17 +6,78 @@ android:layout_height="match_parent" tools:context=".ui.gallery.GalleryFragment"> - + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file