Supported pdf viewing is there.
This commit is contained in:
parent
925a0b841c
commit
a92f970aaf
9 changed files with 177 additions and 38 deletions
|
@ -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"
|
||||||
|
|
|
@ -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 ->
|
||||||
|
FolderTree(
|
||||||
value = file,
|
value = file,
|
||||||
ownPath = "${tree.ownPath}/${file.id}",
|
ownPath = "${tree.ownPath}/${file.id}",
|
||||||
parent = tree
|
parent = tree
|
||||||
) }
|
|
||||||
)
|
)
|
||||||
Log.e("CURRENT", "populateTree: ${tree.value}", )
|
}
|
||||||
Log.e("CHILDREN", "populateTree: ${responseBody.files}", )
|
)
|
||||||
|
tree.loaded = true
|
||||||
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?", )
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 ->
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
4
app/src/main/res/xml/file_paths.xml
Normal file
4
app/src/main/res/xml/file_paths.xml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths>
|
||||||
|
<cache-path name="cache" path="." />
|
||||||
|
</paths>
|
Loading…
Add table
Reference in a new issue