Skip to content

Commit fd6c205

Browse files
committed
Add bottomsheet to print, share, add to kDrive and open with
1 parent f6ca1fe commit fd6c205

11 files changed

+520
-82
lines changed

.idea/navEditor.xml

+55
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewPDFActivity.kt

+142-9
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,69 @@
1717
*/
1818
package com.infomaniak.drive.ui.fileList.preview
1919

20+
import android.content.Context
2021
import android.content.Intent
2122
import android.net.Uri
2223
import android.os.Bundle
24+
import android.os.CancellationSignal
25+
import android.os.ParcelFileDescriptor
26+
import android.print.*
27+
import android.view.View
2328
import androidx.appcompat.app.AppCompatActivity
2429
import androidx.core.view.ViewCompat
2530
import androidx.core.view.WindowInsetsCompat
2631
import androidx.navigation.NavController
2732
import androidx.navigation.fragment.NavHostFragment
33+
import com.google.android.material.bottomsheet.BottomSheetBehavior
2834
import com.infomaniak.drive.R
35+
import com.infomaniak.drive.data.models.ExtensionType
36+
import com.infomaniak.drive.data.models.File
2937
import com.infomaniak.drive.databinding.ActivityPreviewPdfBinding
3038
import com.infomaniak.drive.ui.SaveExternalFilesActivity
3139
import com.infomaniak.drive.ui.SaveExternalFilesActivityArgs
3240
import com.infomaniak.drive.utils.AccountUtils
41+
import com.infomaniak.drive.utils.IOFile
42+
import com.infomaniak.drive.utils.SyncUtils.uploadFolder
43+
import com.infomaniak.drive.utils.Utils.ROOT_ID
44+
import com.infomaniak.drive.utils.Utils.openWithIntent
3345
import com.infomaniak.drive.utils.setupTransparentStatusBar
46+
import com.infomaniak.drive.utils.shareFile
47+
import com.infomaniak.drive.views.ExternalFileInfoActionsView
48+
import com.infomaniak.lib.core.utils.context
49+
import com.infomaniak.lib.core.utils.getFileNameAndSize
3450
import com.infomaniak.lib.core.utils.setMargins
51+
import java.io.FileInputStream
52+
import java.io.FileOutputStream
53+
import java.io.InputStream
54+
import java.io.OutputStream
3555

36-
class PreviewPDFActivity : AppCompatActivity() {
56+
class PreviewPDFActivity : AppCompatActivity(), ExternalFileInfoActionsView.OnItemClickListener {
57+
58+
private val navController by lazy { setupNavController() }
59+
private val navHostFragment by lazy { supportFragmentManager.findFragmentById(R.id.hostFragment) as NavHostFragment }
3760

3861
private val binding: ActivityPreviewPdfBinding by lazy { ActivityPreviewPdfBinding.inflate(layoutInflater) }
3962

63+
private val externalPDFUri: Uri by lazy { Uri.parse(intent.dataString) }
64+
private val fileNameAndSize: Pair<String, Long>? by lazy { getFileNameAndSize(Uri.parse(intent.dataString!!)) }
65+
private val fileName: String by lazy { fileNameAndSize?.first ?: "Document to print" }
66+
private val fileSize: Long? by lazy { fileNameAndSize?.second }
67+
68+
private lateinit var bottomSheetBehavior: BottomSheetBehavior<View>
69+
4070
override fun onCreate(savedInstanceState: Bundle?) {
4171
super.onCreate(savedInstanceState)
4272
setContentView(binding.root)
43-
setupNavController().navigate(R.id.previewPDFFragment)
73+
navController.navigate(R.id.previewPDFFragment)
4474

45-
binding.backButton.setOnClickListener { finish() }
46-
binding.saveToKDrive.setOnClickListener { saveToKDrive(Uri.parse(intent.dataString)) }
75+
with(binding) {
76+
backButton.setOnClickListener { finish() }
77+
intent.dataString?.let {
78+
bottomSheetFileInfos.updateWithExternalFile(getFile())
79+
bottomSheetFileInfos.init(this@PreviewPDFActivity)
80+
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheetFileInfos)
81+
}
82+
}
4783
}
4884

4985
override fun onStart() {
@@ -52,6 +88,38 @@ class PreviewPDFActivity : AppCompatActivity() {
5288
setupTransparentStatusBar()
5389
}
5490

91+
override fun openWithClicked(context: Context) {
92+
super.openWithClicked(context)
93+
startActivity(openWithIntent(externalPDFUri))
94+
}
95+
96+
override fun shareFile(context: Context) {
97+
super.shareFile(context)
98+
shareFile { externalPDFUri }
99+
}
100+
101+
override fun saveToKDriveClicked(context: Context) {
102+
super.saveToKDriveClicked(context)
103+
saveToKDrive(externalPDFUri)
104+
}
105+
106+
override fun printClicked(context: Context) {
107+
super.printClicked(context)
108+
val printManager = getSystemService(Context.PRINT_SERVICE) as PrintManager
109+
val printAdapter = PDFDocumentAdapter(fileName, getOutputFile(externalPDFUri))
110+
printManager.print(fileName, printAdapter, PrintAttributes.Builder().build())
111+
}
112+
113+
private fun getFile(): File {
114+
return File().apply {
115+
name = fileName
116+
size = fileSize
117+
id = ROOT_ID
118+
extensionType = ExtensionType.PDF.value
119+
type = ""
120+
}
121+
}
122+
55123
private fun saveToKDrive(uri: Uri) {
56124
Intent(this, SaveExternalFilesActivity::class.java).apply {
57125
action = Intent.ACTION_SEND
@@ -70,17 +138,82 @@ class PreviewPDFActivity : AppCompatActivity() {
70138
private fun setupWindowInsetsListener() = with(binding) {
71139
ViewCompat.setOnApplyWindowInsetsListener(root) { _, windowInsets ->
72140
with(windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())) {
73-
header.setMargins(left = left, top = top, right = right)
141+
val defaultMargin = context.resources.getDimension(R.dimen.marginStandardMedium).toInt()
142+
backButton.setMargins(top = top + defaultMargin)
143+
/* Add padding to the bottom to allow the last element of the list to be displayed right over the
144+
android navigation bar */
145+
bottomSheetFileInfos.setPadding(0, 0, 0, bottom)
74146
}
75147
windowInsets
76148
}
77149
}
78150

79-
private fun getNavHostFragment() = supportFragmentManager.findFragmentById(R.id.hostFragment) as NavHostFragment
80-
81151
private fun setupNavController(): NavController {
82-
return getNavHostFragment().navController.apply {
83-
setGraph(R.navigation.view_pdf, PreviewPDFFragmentArgs(fileURI = intent.dataString).toBundle())
152+
return navHostFragment.navController.apply {
153+
intent.dataString?.let {
154+
setGraph(R.navigation.view_pdf, PreviewPDFFragmentArgs(fileURI = it).toBundle())
155+
}
156+
}
157+
}
158+
159+
private fun getOutputFile(uri: Uri): IOFile {
160+
return IOFile(uploadFolder, uri.hashCode().toString()).apply {
161+
if (exists()) delete()
162+
createNewFile()
163+
contentResolver?.openInputStream(uri)?.use { inputStream ->
164+
outputStream().use { inputStream.copyTo(it) }
165+
}
166+
}
167+
}
168+
}
169+
170+
class PDFDocumentAdapter(private val fileName: String, private val file: java.io.File) : PrintDocumentAdapter() {
171+
172+
override fun onLayout(
173+
oldAttributes: PrintAttributes?,
174+
newAttributes: PrintAttributes?,
175+
cancellationSignal: CancellationSignal,
176+
callback: LayoutResultCallback,
177+
extras: Bundle?
178+
) {
179+
if (cancellationSignal.isCanceled) {
180+
callback.onLayoutCancelled()
181+
return
182+
}
183+
184+
val info = PrintDocumentInfo.Builder(fileName)
185+
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
186+
.setPageCount(PrintDocumentInfo.PAGE_COUNT_UNKNOWN)
187+
.build()
188+
189+
callback.onLayoutFinished(info, oldAttributes != newAttributes)
190+
}
191+
192+
override fun onWrite(
193+
pages: Array<out PageRange>,
194+
destination: ParcelFileDescriptor,
195+
cancellationSignal: CancellationSignal,
196+
callback: WriteResultCallback
197+
) {
198+
var inputStream: InputStream? = null
199+
var outputStream: OutputStream? = null
200+
201+
try {
202+
inputStream = FileInputStream(file)
203+
outputStream = FileOutputStream(destination.fileDescriptor)
204+
205+
inputStream.copyTo(outputStream)
206+
207+
if (cancellationSignal.isCanceled) {
208+
callback.onWriteCancelled()
209+
} else {
210+
callback.onWriteFinished(arrayOf(PageRange.ALL_PAGES))
211+
}
212+
} catch (ex: Exception) {
213+
callback.onWriteFailed(ex.message)
214+
} finally {
215+
inputStream?.close()
216+
outputStream?.close()
84217
}
85218
}
86219
}

app/src/main/java/com/infomaniak/drive/ui/fileList/preview/PreviewPDFFragment.kt

-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import android.os.Bundle
2424
import android.view.LayoutInflater
2525
import android.view.View
2626
import android.view.ViewGroup
27-
import android.widget.TextView
2827
import androidx.core.content.ContextCompat
2928
import androidx.core.view.isGone
3029
import androidx.core.view.isVisible
@@ -40,7 +39,6 @@ import com.infomaniak.drive.ui.fileList.preview.PreviewSliderFragment.Companion.
4039
import com.infomaniak.drive.utils.IOFile
4140
import com.infomaniak.drive.utils.PreviewPDFUtils
4241
import com.infomaniak.lib.core.models.ApiResponse
43-
import com.infomaniak.lib.core.utils.getFileName
4442
import com.infomaniak.lib.core.utils.safeBinding
4543
import com.infomaniak.lib.pdfview.PDFView
4644
import com.infomaniak.lib.pdfview.scroll.DefaultScrollHandle
@@ -182,7 +180,6 @@ class PreviewPDFFragment : PreviewFragment() {
182180
}
183181

184182
private fun getConfigurator(uriString: String?, pdfFile: IOFile?): PDFView.Configurator {
185-
(activity as? PreviewPDFActivity)?.findViewById<TextView>(R.id.pdfName)?.text = requireContext().getFileName(Uri.parse(uriString))
186183
return uriString?.let { binding.pdfView.fromUri(Uri.parse(uriString)) } ?: binding.pdfView.fromFile(pdfFile)
187184
}
188185

app/src/main/java/com/infomaniak/drive/utils/Extensions.kt

+20
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ import com.google.android.material.textfield.TextInputEditText
5252
import com.google.android.material.textfield.TextInputLayout
5353
import com.infomaniak.drive.BuildConfig
5454
import com.infomaniak.drive.BuildConfig.SUPPORT_URL
55+
import com.infomaniak.drive.MatomoDrive.trackFileActionEvent
5556
import com.infomaniak.drive.MatomoDrive.trackShareRightsEvent
5657
import com.infomaniak.drive.R
5758
import com.infomaniak.drive.data.cache.DriveInfosController
59+
import com.infomaniak.drive.data.documentprovider.CloudStorageProvider
5860
import com.infomaniak.drive.data.models.DriveUser
5961
import com.infomaniak.drive.data.models.File
6062
import com.infomaniak.drive.data.models.FileCategory
@@ -78,6 +80,7 @@ import com.infomaniak.lib.core.utils.UtilsUi.openUrl
7880
import com.infomaniak.lib.login.InfomaniakLogin
7981
import handleActionDone
8082
import io.realm.RealmList
83+
import io.sentry.Sentry
8184
import kotlin.math.abs
8285
import kotlin.math.max
8386
import kotlin.math.min
@@ -437,3 +440,20 @@ fun Context.formatShortBinarySize(size: Long, valueOnly: Boolean = false): Strin
437440
Formatter.formatShortFileSize(this, decimalSize)
438441
}
439442
}
443+
444+
fun Context.shareFile(getUriToShare: () -> Uri?) {
445+
trackFileActionEvent("sendFileCopy")
446+
447+
val shareIntent = Intent().apply {
448+
action = Intent.ACTION_SEND
449+
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
450+
putExtra(Intent.EXTRA_STREAM, getUriToShare())
451+
type = "*/*"
452+
}
453+
454+
runCatching {
455+
startActivity(Intent.createChooser(shareIntent, getString(R.string.buttonSendCopy)))
456+
}.onFailure {
457+
Sentry.captureException(it)
458+
}
459+
}

app/src/main/java/com/infomaniak/drive/utils/FileItemUtils.kt

+4-4
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,13 @@ private fun ImageView.displayIcon(
114114
file: File,
115115
isGrid: Boolean,
116116
progressLayout: ProgressLayoutView,
117-
filePreview2: ImageView? = null,
117+
filePreview: ImageView? = null,
118118
) {
119119
scaleType = if (isGrid) ImageView.ScaleType.FIT_CENTER else ImageView.ScaleType.CENTER
120120
when {
121121
file.isFolder() -> displayFolderIcon(file)
122122
file.isDrive() -> displayDriveIcon(file)
123-
else -> displayFileIcon(file, isGrid, progressLayout, filePreview2)
123+
else -> displayFileIcon(file, isGrid, progressLayout, filePreview)
124124
}
125125
}
126126

@@ -137,7 +137,7 @@ private fun ImageView.displayFileIcon(
137137
file: File,
138138
isGrid: Boolean,
139139
progressLayout: ProgressLayoutView,
140-
filePreview2: ImageView? = null,
140+
filePreview: ImageView? = null,
141141
) {
142142
val fileType = file.getFileType()
143143
val isGraphic = fileType == ExtensionType.IMAGE || fileType == ExtensionType.VIDEO
@@ -162,7 +162,7 @@ private fun ImageView.displayFileIcon(
162162
}
163163
}
164164

165-
filePreview2?.load(fileType.icon)
165+
filePreview?.load(fileType.icon)
166166
progressLayout.setupFileProgress(file)
167167
}
168168

app/src/main/java/com/infomaniak/drive/utils/Utils.kt

+11
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import java.util.Date
6363
import kotlin.math.min
6464
import kotlin.math.pow
6565

66+
6667
object Utils {
6768

6869
const val ROOT_ID = 1
@@ -254,6 +255,16 @@ object Utils {
254255
}
255256
}
256257

258+
fun Context.getExtensionType(uri: Uri) = contentResolver.getType(uri)
259+
260+
fun Context.openWithIntent(uri: Uri): Intent {
261+
return Intent().apply {
262+
action = Intent.ACTION_VIEW
263+
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
264+
setDataAndType(uri, getExtensionType(uri))
265+
}
266+
}
267+
257268
fun moveCacheFileToOffline(file: File, cacheFile: java.io.File, offlineFile: java.io.File) {
258269
if (offlineFile.exists()) offlineFile.delete()
259270
cacheFile.copyTo(offlineFile)

0 commit comments

Comments
 (0)