Skip to content

Commit

Permalink
feat: now export highlights to a file after user choose the file name.
Browse files Browse the repository at this point in the history
  • Loading branch information
plateaukao committed Apr 25, 2024
1 parent 11cc681 commit b039ea8
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2537,7 +2537,7 @@ open class BrowserActivity : FragmentActivity(), BrowserController {

override fun showWebArchiveFilePicker() {
val fileName = "${ninjaWebView.title}.mht"
BrowserUnit.createWebArchiveFilePicker(createWebArchivePickerLauncher, fileName)
BrowserUnit.createFilePicker(createWebArchivePickerLauncher, fileName)
}

override fun toggleTtsRead() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package info.plateaukao.einkbro.activity

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.annotation.StringRes
import androidx.compose.foundation.ExperimentalFoundationApi
Expand Down Expand Up @@ -48,32 +50,44 @@ import androidx.navigation.compose.rememberNavController
import info.plateaukao.einkbro.R
import info.plateaukao.einkbro.database.Article
import info.plateaukao.einkbro.database.Highlight
import info.plateaukao.einkbro.preference.ConfigManager
import info.plateaukao.einkbro.unit.BackupUnit
import info.plateaukao.einkbro.unit.BrowserUnit
import info.plateaukao.einkbro.unit.IntentUnit
import info.plateaukao.einkbro.view.NinjaToast
import info.plateaukao.einkbro.view.compose.MyTheme
import info.plateaukao.einkbro.view.dialog.compose.HorizontalSeparator
import info.plateaukao.einkbro.viewmodel.HighlightViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.text.SimpleDateFormat
import java.util.Locale

class HighlightsActivity : ComponentActivity(), KoinComponent {
private val config: ConfigManager by inject()
private val highlightViewModel: HighlightViewModel by viewModels()
private val backupUnit: BackupUnit by lazy { BackupUnit(this) }

private lateinit var exportHighlightsLauncher: ActivityResultLauncher<Intent>

private var highlightsRoute = HighlightsRoute.RouteArticles
private fun showFileChooser(highlightsRoute: HighlightsRoute) {
this.highlightsRoute = highlightsRoute
BrowserUnit.createFilePicker(exportHighlightsLauncher, "highlights.html")
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

exportHighlightsLauncher =
IntentUnit.createResultLauncher(this) {
it.data?.data?.let { uri -> exportHighlights(uri) }
}


setContent {
val navController: NavHostController = rememberNavController()

var showDialog by remember { mutableStateOf(false) }

MyTheme {
val backStackEntry = navController.currentBackStackEntryAsState()
val currentScreen = HighlightsRoute.valueOf(
Expand All @@ -85,7 +99,7 @@ class HighlightsActivity : ComponentActivity(), KoinComponent {
topBar = {
HighlightsBar(
currentScreen = currentScreen,
onClick = { exportHighlights(currentScreen) },
onClick = { showFileChooser(currentScreen) },
navigateUp = {
if (navController.previousBackStackEntry != null) navController.navigateUp()
else finish()
Expand All @@ -108,7 +122,7 @@ class HighlightsActivity : ComponentActivity(), KoinComponent {
?.toInt() ?: 0,
modifier = Modifier.padding(10.dp),
highlightViewModel,
deleteHighlight = { it -> highlightViewModel.deleteHighlight(it) }
deleteHighlight = { highlightViewModel.deleteHighlight(it) }
)
}
}
Expand All @@ -117,25 +131,18 @@ class HighlightsActivity : ComponentActivity(), KoinComponent {
}
}

private fun exportHighlights(currentScreen: HighlightsRoute) {
private fun exportHighlights(uri: Uri) {
highlightViewModel.viewModelScope.launch(Dispatchers.IO) {
if (currentScreen == HighlightsRoute.RouteArticles) {
var data = ""
highlightViewModel.getAllArticlesAsync().forEach { article ->
val articleTitle = highlightViewModel.getArticle(article.id)?.title ?: ""
val highlights = highlightViewModel.getHighlightsForArticleAsync(article.id)
data += "<h1>$articleTitle</h1><br/><hr/><br/>"
data += highlights.joinToString("<br/><br/>") { it.content }
data += "<br/><br/>"
}
backupUnit.exportHighlights(data)
val data = if (highlightsRoute == HighlightsRoute.RouteArticles) {
highlightViewModel.dumpArticlesHighlights()
} else {
val articleId = currentScreen.titleId
val articleTitle = highlightViewModel.getArticle(articleId)?.title ?: ""
val highlights = highlightViewModel.getHighlightsForArticleAsync(articleId)
var data = "<h1>$articleTitle</h1><hr><br/>"
data += highlights.joinToString("<br/><br/>") { it.content }
backupUnit.exportHighlights(data, articleTitle)
highlightViewModel.dumpSingleArticleHighlights(highlightsRoute.articleId)
}
backupUnit.exportHighlights(uri, data)

withContext(Dispatchers.Main) {
NinjaToast.show(this@HighlightsActivity, R.string.toast_backup_successful)
IntentUnit.showFile(this@HighlightsActivity, uri)
}
}
}
Expand All @@ -148,7 +155,7 @@ class HighlightsActivity : ComponentActivity(), KoinComponent {
}
}

enum class HighlightsRoute(@StringRes val titleId: Int) {
enum class HighlightsRoute(@StringRes val articleId: Int) {
RouteArticles(R.string.articles),
RouteHighlights(R.string.highlights),
}
Expand Down Expand Up @@ -290,7 +297,7 @@ fun HighlightsBar(
TopAppBar(
title = {
Text(
stringResource(currentScreen.titleId),
stringResource(currentScreen.articleId),
color = MaterialTheme.colors.onPrimary
)
},
Expand Down
16 changes: 3 additions & 13 deletions app/src/main/java/info/plateaukao/einkbro/unit/BackupUnit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Environment
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResult
Expand Down Expand Up @@ -316,20 +315,11 @@ class BackupUnit(
return uri
}

fun exportHighlights(data: String, fileName: String? = null) {
val fullFileName = (fileName ?: "highlights") + ".html"
fun exportHighlights(uri: Uri, data: String) {
val fileContent = data.toByteArray()

val documentsDir =
context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)
try {
val file = File(documentsDir, fullFileName)
val fileOutputStream = FileOutputStream(file)
fileOutputStream.write(fileContent)
fileOutputStream.close()
shareFile(context as Activity, file)
} catch (e: Exception) {
e.printStackTrace()
context.contentResolver.openOutputStream(uri)?.use { outputStream ->
outputStream.write(fileContent)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ object BrowserUnit : KoinComponent {
resultLauncher.launch(intent)
}

fun createWebArchiveFilePicker(resultLauncher: ActivityResultLauncher<Intent>, title: String) {
fun createFilePicker(resultLauncher: ActivityResultLauncher<Intent>, title: String) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = Constants.MIME_TYPE_ANY
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/info/plateaukao/einkbro/unit/IntentUnit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,14 @@ object IntentUnit {
}
}

fun showFile(activity: Activity, uri: Uri) {
val intent = Intent(ACTION_VIEW).apply {
setDataAndType(uri, "text/html")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
activity.startActivity(intent)
}

fun tts(activity: Activity, text: String) {
val intent = Intent("android.intent.action.PROCESS_TEXT").apply {
type = "text/plain"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,38 @@ class HighlightViewModel : ViewModel(), KoinComponent {

fun getAllArticles() = bookmarkManager.getAllArticles()

suspend fun getAllArticlesAsync() = bookmarkManager.getAllArticlesAsync()
private suspend fun getAllArticlesAsync() = bookmarkManager.getAllArticlesAsync()

suspend fun getArticle(articleId: Int) = bookmarkManager.getArticle(articleId)

suspend fun dumpArticlesHighlights(): String {
val articles = getAllArticlesAsync()
var data = ""
articles.sortedByDescending { it.date }.forEach {
data += dumpSingleArticleHighlights(it.id) + "<br/><br/>"
}
return data
}

suspend fun dumpSingleArticleHighlights(articleId: Int): String {
val article = getArticle(articleId)
val articleTitle = article?.title ?: ""
val highlights = getHighlightsForArticleAsync(articleId)
var data = "<h2>$articleTitle</h2><hr/>"
data += highlights.joinToString("<br/><br/>") { it.content }
data += "<br/><br/>"
return data
}

fun deleteArticle(articleId: Int) {
viewModelScope.launch {
bookmarkManager.deleteArticle(articleId)
}
}

fun getHighlightsForArticle(articleId: Int) =
bookmarkManager.getHighlightsForArticle(articleId)

suspend fun getHighlightsForArticleAsync(articleId: Int) =
bookmarkManager.getHighlightsForArticleAsync(articleId)

Expand Down

0 comments on commit b039ea8

Please sign in to comment.