Supported pdf viewing is there.

This commit is contained in:
AlbYoda 2025-03-24 01:00:36 +01:00
parent 925a0b841c
commit a92f970aaf
Signed by untrusted user who does not match committer: AlbYoda
GPG key ID: A539D876452F16FF
9 changed files with 177 additions and 38 deletions

View file

@ -26,6 +26,16 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.DeNaDrive" android:theme="@style/Theme.DeNaDrive"
tools:targetApi="31"> tools:targetApi="31">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<activity <activity
android:name=".oauth.LoadingActivity" android:name=".oauth.LoadingActivity"
android:exported="false" android:exported="false"

View file

@ -26,7 +26,6 @@ object DriveRequester {
context: Context, context: Context,
tree: FolderTree tree: FolderTree
) { ) {
Log.e("MEOW", "populateTree: got here", )
val myUrl = "https://www.googleapis.com/drive/v3/files?trashed=false&orderBy=folder" val myUrl = "https://www.googleapis.com/drive/v3/files?trashed=false&orderBy=folder"
makeNewRequest( makeNewRequest(
context = context, context = context,
@ -38,25 +37,24 @@ object DriveRequester {
) )
} }
) { response, exception -> ) { response, exception ->
Log.e("MOO", "populateTree: and here", )
if (exception != null) { if (exception != null) {
Log.e("RESPONSE EXCEPTION", "populateTree: ${exception.message}", ) Log.e("RESPONSE EXCEPTION", "populateTree: ${exception.message}")
} else { } else {
val responseBody = ResponsesHandler.newResponseArrived<DriveResponseBody>(response) val responseBody = ResponsesHandler.newResponseArrived<DriveResponseBody>(response)
if (responseBody != null) { if (responseBody != null) {
tree.addChildren( tree.addChildren(
responseBody.files.map { file -> FolderTree( responseBody.files.map { file ->
value = file, FolderTree(
ownPath = "${tree.ownPath}/${file.id}", value = file,
parent = tree ownPath = "${tree.ownPath}/${file.id}",
) } parent = tree
)
}
) )
Log.e("CURRENT", "populateTree: ${tree.value}", ) tree.loaded = true
Log.e("CHILDREN", "populateTree: ${responseBody.files}", )
for (child in tree.getChildren()) { for (child in tree.getChildren()) {
if (!child.isLeaf()) populateTree(context, child) if (!child.isLeaf()) populateTree(context, child)
} }
Log.e("MOO", "populateTree: also here?", )
} }
} }
} }

View file

@ -23,7 +23,8 @@ class FolderTree(
val value: MyFile, val value: MyFile,
val ownPath: String = value.id, val ownPath: String = value.id,
private val children: MutableList<FolderTree> = mutableListOf(), private val children: MutableList<FolderTree> = mutableListOf(),
val parent: FolderTree? = null val parent: FolderTree? = null,
var loaded: Boolean = false
) { ) {
fun isLeaf(): Boolean { fun isLeaf(): Boolean {

View file

@ -57,7 +57,7 @@ class HomeNotAuthActivity : ComponentActivity() {
DeNaDriveTheme { DeNaDriveTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
val logo = painterResource(id = R.drawable.vecchiaicona_) val logo = painterResource(id = R.drawable.vecchiaicona_)
LogoWithCaptionAndButton ( LogoWithCaptionAndButton(
logo = logo, logo = logo,
caption = "DeNa Drive", caption = "DeNa Drive",
buttonText = "Log in", buttonText = "Log in",
@ -77,16 +77,25 @@ class HomeNotAuthActivity : ComponentActivity() {
"com.bbc.denadrive:/oauth2redirect".toUri() "com.bbc.denadrive:/oauth2redirect".toUri()
) )
val authRequest = authRequestBuilder val authRequest = authRequestBuilder
.setScope("https://www.googleapis.com/auth/drive") .setScopes(
listOf(
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.apps"
)
)
.build() .build()
val authService = AuthorizationService(this) val authService = AuthorizationService(this)
authService.performAuthorizationRequest( authService.performAuthorizationRequest(
authRequest, authRequest,
PendingIntent.getActivity(this, 0, Intent(this, LoadingActivity::class.java), PendingIntent.getActivity(
PendingIntent.FLAG_MUTABLE), this, 0, Intent(this, LoadingActivity::class.java),
PendingIntent.getActivity(this, 0, Intent(this, HomeNotAuthActivity::class.java), PendingIntent.FLAG_MUTABLE
PendingIntent.FLAG_MUTABLE) ),
PendingIntent.getActivity(
this, 0, Intent(this, HomeNotAuthActivity::class.java),
PendingIntent.FLAG_MUTABLE
)
) )
} }
} }

View file

@ -32,6 +32,7 @@ import com.bbc.denadrive.apihandlers.MyFile
import com.bbc.denadrive.apihandlers.ResponsesHandler import com.bbc.denadrive.apihandlers.ResponsesHandler
import com.bbc.denadrive.apihandlers.ResponsesViewer import com.bbc.denadrive.apihandlers.ResponsesViewer
import com.bbc.denadrive.apihandlers.makeDriveApiCall import com.bbc.denadrive.apihandlers.makeDriveApiCall
import com.bbc.denadrive.filehandling.FileDownloader
import com.bbc.denadrive.home.ScaffoldWithSidebar import com.bbc.denadrive.home.ScaffoldWithSidebar
import com.bbc.denadrive.oauth.AuthStatePersistence import com.bbc.denadrive.oauth.AuthStatePersistence
import com.bbc.denadrive.ui.theme.DeNaDriveTheme import com.bbc.denadrive.ui.theme.DeNaDriveTheme
@ -42,7 +43,12 @@ import okhttp3.HttpUrl
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
private lateinit var responsesViewer: ResponsesViewer private lateinit var responsesViewer: ResponsesViewer
private var currentPath: String = "root" private val exportSupportedFiles: List<String> = listOf(
"document",
"drawing",
"presentation",
"spreadsheet",
)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -64,6 +70,7 @@ class MainActivity : ComponentActivity() {
finish() finish()
} }
} }
val fileDownloader = FileDownloader(this)
// goToFolder(parentFolder = "root", forward = true, isFirstRequest = true) // goToFolder(parentFolder = "root", forward = true, isFirstRequest = true)
@ -71,16 +78,28 @@ class MainActivity : ComponentActivity() {
// val navController = rememberNavController() // val navController = rememberNavController()
ScaffoldWithSidebar( ScaffoldWithSidebar(
responsesViewer, responsesViewer,
{ name -> { file ->
Toast.makeText( Toast.makeText(
this, this,
"You pressed the file $name", "You pressed the file ${file.name}",
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
if (file.mimeType.substringAfterLast(".") in exportSupportedFiles) {
fileDownloader.downloadFile(
"https://www.googleapis.com/drive/v3/files/${file.id}/export",
"application/pdf"
)
} else {
Toast.makeText(
this,
"This file has no default action. Download support coming soon",
Toast.LENGTH_SHORT
).show()
}
}, },
{ folder -> { folder ->
responsesViewer.currentFolderTree.value = responsesViewer.currentFolderTree.value =
responsesViewer.currentFolderTree.value.stepForward(folder) responsesViewer.currentFolderTree.value.stepForward(folder.id)
// responsesViewer.currentFolderTree.value = // responsesViewer.currentFolderTree.value =
// responsesViewer.currentFolderTree.value.goToPath("$folder/") // responsesViewer.currentFolderTree.value.goToPath("$folder/")
// parent -> // parent ->
@ -94,10 +113,17 @@ class MainActivity : ComponentActivity() {
} }
// private fun getApps() { private fun getApps() {
// val myUrl = "https://www.googleapis.com/drive/v3/apps" val myUrl = "https://www.googleapis.com/drive/v3/apps"
// makeNewRequest(myUrl) { } DriveRequester.makeNewRequest(this, myUrl, { }) {
// } response, exception ->
if (exception != null) {
Log.e("notGood", "getApps: $exception", )
} else {
Log.e("GOOD", "getApps: $response", )
}
}
}
// private fun askForFolder(folderId: String) { // private fun askForFolder(folderId: String) {
// val myUrl = "https://www.googleapis.com/drive/v3/files" // val myUrl = "https://www.googleapis.com/drive/v3/files"

View file

@ -32,8 +32,9 @@ fun makeDriveApiCall(
authState: AuthState, authState: AuthState,
url: String, url: String,
// folderId: String, // folderId: String,
builderModifier:(HttpUrl.Builder) -> Unit, builderModifier: (HttpUrl.Builder) -> Unit,
callback: (String?, Exception?) -> Unit) { callback: (String?, Exception?) -> Unit
) {
val authService = AuthorizationService(context) val authService = AuthorizationService(context)
// _ = idToken // _ = idToken
authState.performActionWithFreshTokens(authService) { accessToken, _, ex -> authState.performActionWithFreshTokens(authService) { accessToken, _, ex ->

View file

@ -0,0 +1,88 @@
package com.bbc.denadrive.filehandling
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.core.content.FileProvider
import com.bbc.denadrive.oauth.AuthStatePersistence
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
class FileDownloader(private val context: Context) {
fun downloadFile(fileUrl: String, mimeType: String) {
CoroutineScope(Dispatchers.IO).launch {
val tempFile = downloadIt(fileUrl, mimeType)
withContext(Dispatchers.Main) {
tempFile?.let {
openFile(it)
}
}
}
}
private fun downloadIt(fileUrl: String, mimeType: String): File? {
var tempFile: File? = null
val authState = AuthStatePersistence.retrieveAuthState(context)
try {
tempFile = File.createTempFile("tempFile", ".pdf", context.cacheDir)
// val builder = fileUrl.toHttpUrl().newBuilder()
// builder.addQueryParameter("mimeType", mimeType)
// val urlConnection = builder.build().toUrl().openConnection() as HttpURLConnection
val urlConnection = URL("$fileUrl?mimeType=application/pdf").openConnection() as HttpURLConnection
urlConnection.setRequestProperty("Authorization", "Bearer ${authState.accessToken}")
urlConnection.connect()
// val inputStream1 = urlConnection.inputStream
// val buffer1 = ByteArray(4)
// inputStream1.read(buffer1)
// val header = String(buffer1)
// if (!header.startsWith("%PDF")) {
// Log.e("FileDownloader", "Downloaded file is not a valid PDF")
// }
if (urlConnection.responseCode == HttpURLConnection.HTTP_OK) {
Log.e("MA", "downloadIt: andato", )
val inputStream = urlConnection.inputStream
val outputStream = FileOutputStream(tempFile)
val buffer = ByteArray(1024)
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
}
outputStream.close()
inputStream.close()
urlConnection.disconnect()
} else {
Log.e("FileDownloader", "Error: ${urlConnection.responseCode} - ${urlConnection.responseMessage}")
}
} catch (e: Exception) {
Log.e("FileDownloader", "downloadIt: download failed", e)
}
return tempFile
}
private fun openFile(file: File) {
val uri: Uri = FileProvider.getUriForFile(context, "${context.packageName}.fileprovider", file)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(uri, "application/pdf")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
context.startActivity(intent)
}
}

View file

@ -53,8 +53,8 @@ import com.bbc.denadrive.apihandlers.ResponsesViewer
@Composable @Composable
fun ScaffoldWithSidebar( fun ScaffoldWithSidebar(
responsesViewer: ResponsesViewer, responsesViewer: ResponsesViewer,
onFileClick: (String) -> Unit, onFileClick: (MyFile) -> Unit,
onFolderClick: (String) -> Unit, onFolderClick: (MyFile) -> Unit,
doIt: () -> Unit, doIt: () -> Unit,
) { ) {
// State to control the drawer // State to control the drawer
@ -245,8 +245,8 @@ fun Loading(
@Composable @Composable
fun AnotherVisualizer( fun AnotherVisualizer(
responsesViewer: ResponsesViewer, responsesViewer: ResponsesViewer,
onFileClick: (String) -> Unit, onFileClick: (MyFile) -> Unit,
onFolderClick: (String) -> Unit onFolderClick: (MyFile) -> Unit
) { ) {
val currentFolderTree = responsesViewer.currentFolderTree.value val currentFolderTree = responsesViewer.currentFolderTree.value
val updater1 = responsesViewer.updater1.value val updater1 = responsesViewer.updater1.value
@ -256,6 +256,10 @@ fun AnotherVisualizer(
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(text = "How did you get here? You're inside a file...") Text(text = "How did you get here? You're inside a file...")
} }
} else if (!currentFolderTree.loaded) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Loading()
}
} else if (currentFolderTree.getChildren().isEmpty()) { } else if (currentFolderTree.getChildren().isEmpty()) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text("Empty folder") Text("Empty folder")
@ -263,8 +267,8 @@ fun AnotherVisualizer(
} }
} else { } else {
val fileList = currentFolderTree.getChildren().map { tree -> tree.value } val fileList = currentFolderTree.getChildren().map { tree -> tree.value }
Log.e("Visualizer", "AnotherVisualizer: ${currentFolderTree.value}", ) // Log.e("Visualizer", "AnotherVisualizer: ${currentFolderTree.value}", )
Log.e("Visualizer", "AnotherVisualizer: ${currentFolderTree.getChildren()}", ) // Log.e("Visualizer", "AnotherVisualizer: ${currentFolderTree.getChildren()}", )
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter) {
LazyColumn { LazyColumn {
items(fileList) { file -> items(fileList) { file ->
@ -273,9 +277,7 @@ fun AnotherVisualizer(
val onClick = if (isFolder) onFolderClick val onClick = if (isFolder) onFolderClick
else onFileClick else onFileClick
LogoTextBox(logo, file.name) { LogoTextBox(logo, file.name) {
onClick( onClick(file)
if (isFolder) file.id else file.name
)
} }
} }
} }
@ -284,7 +286,7 @@ fun AnotherVisualizer(
} }
fun getId(mimeType: String): Int { fun getId(mimeType: String): Int {
val extracted = mimeType.drop("application/vnd.google-apps.".length) val extracted = mimeType.substringAfterLast(".")
return when (extracted) { return when (extracted) {
"document" -> R.drawable.docslogo_ok "document" -> R.drawable.docslogo_ok
"presentation" -> R.drawable.slideslogo_ok "presentation" -> R.drawable.slideslogo_ok

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<cache-path name="cache" path="." />
</paths>