c2c-sync/app/src/main/java/com/nextcloud/client/documentscan/DocumentScanActivity.kt
2025-09-18 17:54:51 +02:00

203 lines
6.8 KiB
Kotlin

/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package com.nextcloud.client.documentscan
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.activity.result.ActivityResultLauncher
import androidx.appcompat.app.AlertDialog
import androidx.core.view.MenuProvider
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.client.di.Injectable
import com.nextcloud.client.di.ViewModelFactory
import com.nextcloud.client.logger.Logger
import com.owncloud.android.R
import com.owncloud.android.databinding.ActivityDocumentScanBinding
import com.owncloud.android.databinding.DialogScanExportTypeBinding
import com.owncloud.android.ui.activity.ToolbarActivity
import com.owncloud.android.utils.theme.ViewThemeUtils
import javax.inject.Inject
class DocumentScanActivity : ToolbarActivity(), Injectable {
@Inject
lateinit var vmFactory: ViewModelFactory
@Inject
lateinit var logger: Logger
@Inject
lateinit var viewThemeUtils: ViewThemeUtils
@Inject
lateinit var appScanOptionalFeature: AppScanOptionalFeature
lateinit var binding: ActivityDocumentScanBinding
lateinit var viewModel: DocumentScanViewModel
private var scanPage: ActivityResultLauncher<Unit>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
scanPage = registerForActivityResult(appScanOptionalFeature.getScanContract()) { result ->
viewModel.onScanPageResult(result)
}
val folder = intent.extras?.getString(EXTRA_FOLDER)
require(folder != null) { "Folder must be provided for upload" }
viewModel = ViewModelProvider(this, vmFactory)[DocumentScanViewModel::class.java]
viewModel.setUploadFolder(folder)
setupViews()
observeState()
}
private fun setupViews() {
binding = ActivityDocumentScanBinding.inflate(layoutInflater)
setContentView(binding.root)
setupToolbar()
supportActionBar?.let {
it.setDisplayHomeAsUpEnabled(true)
it.setDisplayShowHomeEnabled(true)
viewThemeUtils.files.themeActionBar(this, it)
}
viewThemeUtils.material.themeFAB(binding.fab)
binding.fab.setOnClickListener {
viewModel.onAddPageClicked()
}
binding.pagesRecycler.layoutManager = GridLayoutManager(this, PAGE_COLUMNS)
setupMenu()
}
private fun setupMenu() {
addMenuProvider(
object : MenuProvider {
override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
menuInflater.inflate(R.menu.activity_document_scan, menu)
menu.findItem(R.id.action_save)?.let {
viewThemeUtils.platform.colorToolbarMenuIcon(this@DocumentScanActivity, it)
}
}
override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
return when (menuItem.itemId) {
R.id.action_save -> {
viewModel.onClickDone()
true
}
android.R.id.home -> {
onBackPressed()
true
}
else -> false
}
}
}
)
}
private fun observeState() {
viewModel.uiState.observe(this, ::handleState)
}
private fun handleState(state: DocumentScanViewModel.UIState) {
logger.d(TAG, "handleState: called with $state")
when (state) {
is DocumentScanViewModel.UIState.BaseState -> when (state) {
is DocumentScanViewModel.UIState.NormalState -> {
updateButtonsEnabled(true)
val pageList = state.pageList
updateRecycler(pageList)
if (state.shouldRequestScan) {
startPageScan()
}
}
is DocumentScanViewModel.UIState.RequestExportState -> {
updateButtonsEnabled(false)
if (state.shouldRequestExportType) {
showExportDialog()
viewModel.onRequestTypeHandled()
}
}
}
DocumentScanViewModel.UIState.DoneState, DocumentScanViewModel.UIState.CanceledState -> {
finish()
}
}
}
private fun showExportDialog() {
val dialogBinding = DialogScanExportTypeBinding.inflate(layoutInflater)
val dialog = MaterialAlertDialogBuilder(this)
.setTitle(R.string.document_scan_export_dialog_title)
.setCancelable(true)
.setView(dialogBinding.root)
.setNegativeButton(R.string.common_cancel) { _, _ ->
viewModel.onExportCanceled()
}
.setOnCancelListener { viewModel.onExportCanceled() }
.also {
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(this@DocumentScanActivity, it)
}
.create()
viewThemeUtils.platform.colorTextButtons(dialogBinding.btnPdf, dialogBinding.btnImages)
dialogBinding.btnPdf.setOnClickListener {
viewModel.onExportTypeSelected(DocumentScanViewModel.ExportType.PDF)
dialog.dismiss()
}
dialogBinding.btnImages.setOnClickListener {
viewModel.onExportTypeSelected(DocumentScanViewModel.ExportType.IMAGES)
dialog.dismiss()
}
dialog.setOnShowListener {
val alertDialog = it as AlertDialog
viewThemeUtils.platform.colorTextButtons(alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE))
}
dialog.show()
}
private fun updateRecycler(pageList: List<String>) {
if (binding.pagesRecycler.adapter == null) {
binding.pagesRecycler.adapter = DocumentPageListAdapter()
}
(binding.pagesRecycler.adapter as? DocumentPageListAdapter)?.submitList(pageList)
}
private fun updateButtonsEnabled(enabled: Boolean) {
binding.fab.isEnabled = enabled
}
private fun startPageScan() {
logger.d(TAG, "startPageScan() called")
viewModel.onScanRequestHandled()
scanPage!!.launch(Unit)
}
companion object {
private const val TAG = "DocumentScanActivity"
private const val PAGE_COLUMNS = 2
const val EXTRA_FOLDER = "extra_folder"
}
}