diff --git a/app/src/main/java/se/ajpanton/notificationlog/ViewLogsFragment.kt b/app/src/main/java/se/ajpanton/notificationlog/ViewLogsFragment.kt index 2e4a63a..dc1fec6 100644 --- a/app/src/main/java/se/ajpanton/notificationlog/ViewLogsFragment.kt +++ b/app/src/main/java/se/ajpanton/notificationlog/ViewLogsFragment.kt @@ -3,6 +3,7 @@ package se.ajpanton.notificationlog import android.os.Bundle import android.content.ComponentName import android.content.Intent +import android.net.Uri import android.provider.Settings import android.view.View import android.widget.TextView @@ -15,11 +16,17 @@ import se.ajpanton.notificationlog.settings.LogField import se.ajpanton.notificationlog.settings.LogViewSettingsStore import se.ajpanton.notificationlog.settings.TimestampZone import se.ajpanton.notificationlog.capture.NotificationCaptureService +import se.ajpanton.notificationlog.export.LogExporter +import java.util.zip.ZipOutputStream import java.text.DateFormat import java.util.Date class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) { private var binding: FragmentViewLogsBinding? = null + private var pendingExport: ExportFormat? = null + private val createDocument = registerForActivityResult(androidx.activity.result.contract.ActivityResultContracts.CreateDocument("application/octet-stream")) { uri -> + uri?.let(::writeExport) + } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -27,6 +34,7 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) { binding!!.notificationAccess.setOnClickListener { startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS)) } + binding!!.exportLogs.setOnClickListener { chooseExportFormat() } binding!!.clearLogs.setOnClickListener { MaterialAlertDialogBuilder(requireContext()) .setTitle("Clear logs?") @@ -90,4 +98,32 @@ class ViewLogsFragment : Fragment(R.layout.fragment_view_logs) { ComponentName(requireContext(), NotificationCaptureService::class.java), ) } + + private fun chooseExportFormat() { + MaterialAlertDialogBuilder(requireContext()) + .setItems(arrayOf("CSV", "Formatted text", "HTML ZIP")) { _, which -> + pendingExport = ExportFormat.entries[which] + createDocument.launch("notification-log.${pendingExport!!.extension}") + }.show() + } + + private fun writeExport(uri: Uri) { + val format = pendingExport ?: return + val context = requireContext().applicationContext + Thread { + val entries = EncryptedNotificationLogStore(context).readAll() + val settings = LogViewSettingsStore(context).load() + context.contentResolver.openOutputStream(uri)?.use { output -> when (format) { + ExportFormat.CSV -> output.write(LogExporter.csv(entries, settings).encodeToByteArray()) + ExportFormat.FORMATTED -> output.write(LogExporter.formatted(entries, settings).encodeToByteArray()) + ExportFormat.HTML_ZIP -> ZipOutputStream(output).use { zip -> + zip.putNextEntry(java.util.zip.ZipEntry("notification-log.html")) + zip.write(LogExporter.html(entries, settings).encodeToByteArray()) + zip.closeEntry() + } + } } + }.start() + } + + private enum class ExportFormat(val extension: String) { CSV("csv"), FORMATTED("txt"), HTML_ZIP("zip") } } diff --git a/app/src/main/res/layout/fragment_view_logs.xml b/app/src/main/res/layout/fragment_view_logs.xml index f1065dd..c574a2a 100644 --- a/app/src/main/res/layout/fragment_view_logs.xml +++ b/app/src/main/res/layout/fragment_view_logs.xml @@ -1,6 +1,6 @@ -