diff --git a/app/src/main/java/info/plateaukao/einkbro/activity/BrowserActivity.kt b/app/src/main/java/info/plateaukao/einkbro/activity/BrowserActivity.kt index 8d0fcecf..fa8252b2 100755 --- a/app/src/main/java/info/plateaukao/einkbro/activity/BrowserActivity.kt +++ b/app/src/main/java/info/plateaukao/einkbro/activity/BrowserActivity.kt @@ -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() { diff --git a/app/src/main/java/info/plateaukao/einkbro/activity/HighlightsActivity.kt b/app/src/main/java/info/plateaukao/einkbro/activity/HighlightsActivity.kt index b4dfc34d..8a40ce15 100644 --- a/app/src/main/java/info/plateaukao/einkbro/activity/HighlightsActivity.kt +++ b/app/src/main/java/info/plateaukao/einkbro/activity/HighlightsActivity.kt @@ -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 @@ -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 + + 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( @@ -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() @@ -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) } ) } } @@ -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 += "

$articleTitle




" - data += highlights.joinToString("

") { it.content } - data += "

" - } - 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 = "

$articleTitle



" - data += highlights.joinToString("

") { 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) } } } @@ -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), } @@ -290,7 +297,7 @@ fun HighlightsBar( TopAppBar( title = { Text( - stringResource(currentScreen.titleId), + stringResource(currentScreen.articleId), color = MaterialTheme.colors.onPrimary ) }, diff --git a/app/src/main/java/info/plateaukao/einkbro/unit/BackupUnit.kt b/app/src/main/java/info/plateaukao/einkbro/unit/BackupUnit.kt index 72efbc50..70d085ab 100644 --- a/app/src/main/java/info/plateaukao/einkbro/unit/BackupUnit.kt +++ b/app/src/main/java/info/plateaukao/einkbro/unit/BackupUnit.kt @@ -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 @@ -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) } } diff --git a/app/src/main/java/info/plateaukao/einkbro/unit/BrowserUnit.kt b/app/src/main/java/info/plateaukao/einkbro/unit/BrowserUnit.kt index 8a864ed4..9fc81c08 100755 --- a/app/src/main/java/info/plateaukao/einkbro/unit/BrowserUnit.kt +++ b/app/src/main/java/info/plateaukao/einkbro/unit/BrowserUnit.kt @@ -522,7 +522,7 @@ object BrowserUnit : KoinComponent { resultLauncher.launch(intent) } - fun createWebArchiveFilePicker(resultLauncher: ActivityResultLauncher, title: String) { + fun createFilePicker(resultLauncher: ActivityResultLauncher, title: String) { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) intent.addCategory(Intent.CATEGORY_OPENABLE) intent.type = Constants.MIME_TYPE_ANY diff --git a/app/src/main/java/info/plateaukao/einkbro/unit/IntentUnit.kt b/app/src/main/java/info/plateaukao/einkbro/unit/IntentUnit.kt index 284b4d97..9ad3b1ae 100755 --- a/app/src/main/java/info/plateaukao/einkbro/unit/IntentUnit.kt +++ b/app/src/main/java/info/plateaukao/einkbro/unit/IntentUnit.kt @@ -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" diff --git a/app/src/main/java/info/plateaukao/einkbro/viewmodel/HighlightViewModel.kt b/app/src/main/java/info/plateaukao/einkbro/viewmodel/HighlightViewModel.kt index 6d68b323..696efd77 100644 --- a/app/src/main/java/info/plateaukao/einkbro/viewmodel/HighlightViewModel.kt +++ b/app/src/main/java/info/plateaukao/einkbro/viewmodel/HighlightViewModel.kt @@ -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) + "

" + } + return data + } + + suspend fun dumpSingleArticleHighlights(articleId: Int): String { + val article = getArticle(articleId) + val articleTitle = article?.title ?: "" + val highlights = getHighlightsForArticleAsync(articleId) + var data = "

$articleTitle


" + data += highlights.joinToString("

") { it.content } + data += "

" + 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)