Included XML in the list of supported export formats

This commit is contained in:
Om Godse 2021-07-14 16:37:36 +05:30
parent 18a8816837
commit 471de05c96
13 changed files with 71 additions and 28 deletions

View file

@ -1,4 +1,4 @@
*Please use the issues tab only for bug reports* *Please use the pull requests tab only for translations or bug reports*
### Background ### Background
Although there are many notes apps out there, they're all hideous, glitchy, low quality or all 3 at the same time. Although there are many notes apps out there, they're all hideous, glitchy, low quality or all 3 at the same time.
@ -23,7 +23,7 @@ Well, Notally is none of these things. It's extremely light, minimalistic and el
* APK size of 1.5 MB (1.9 MB Uncompressed) * APK size of 1.5 MB (1.9 MB Uncompressed)
* Add labels to your notes for quick organisation * Add labels to your notes for quick organisation
* Archive notes to keep them around, but out of your way * Archive notes to keep them around, but out of your way
* Export notes as plain text, HTML or PDF files with formatting * Export notes as plain text, XML, HTML or PDF files with formatting
* Create rich text notes with support for bold, italics, mono space and strike-through * Create rich text notes with support for bold, italics, mono space and strike-through
* Add clickable links to notes with support for phone numbers, email addresses and web urls * Add clickable links to notes with support for phone numbers, email addresses and web urls

View file

@ -13,9 +13,9 @@ android {
applicationId "com.omgodse.notally" applicationId "com.omgodse.notally"
minSdkVersion rootProject.ext.minSdkVersion minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 33 versionCode 34
versionName "3.8" versionName "3.9"
resConfigs "en", "ca", "cs", "de", "es", "fr", "hu", "in", "it", "ja", "nb", "nl", "pl", "pt-rBR", "ru", "sv", "tl", "tr", "uk" resConfigs "en", "ca", "cs", "de", "es", "fr", "hu", "in", "it", "ja", "nb", "nl", "pl", "pt-rBR", "ru", "sk", "sv", "tl", "tr", "uk"
vectorDrawables.generatedDensities = [] vectorDrawables.generatedDensities = []
} }
@ -56,7 +56,7 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$navVersion" implementation "androidx.navigation:navigation-fragment-ktx:$navVersion"
implementation "org.ocpsoft.prettytime:prettytime:4.0.6.Final" implementation "org.ocpsoft.prettytime:prettytime:4.0.6.Final"
implementation "com.google.android.material:material:1.3.0" implementation "com.google.android.material:material:1.4.0"
implementation project(":Post") implementation project(":Post")
} }

View file

@ -11,6 +11,7 @@ import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.Toast import android.widget.Toast
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
@ -140,10 +141,7 @@ abstract class NotallyFragment : Fragment(), OperationsParent, ItemListener {
private fun setupObserver() { private fun setupObserver() {
getObservable()?.observe(viewLifecycleOwner, { list -> getObservable()?.observe(viewLifecycleOwner, { list ->
adapter?.submitList(list) adapter?.submitList(list)
binding?.RecyclerView?.isVisible = list.isNotEmpty()
if (list.isNotEmpty()) {
binding?.RecyclerView?.visibility = View.VISIBLE
} else binding?.RecyclerView?.visibility = View.GONE
}) })
} }
@ -176,6 +174,7 @@ abstract class NotallyFragment : Fragment(), OperationsParent, ItemListener {
MenuDialog(mContext) MenuDialog(mContext)
.addItem(Operation(R.string.pdf, R.drawable.pdf) { exportBaseNoteToPDF(baseNote) }) .addItem(Operation(R.string.pdf, R.drawable.pdf) { exportBaseNoteToPDF(baseNote) })
.addItem(Operation(R.string.txt, R.drawable.txt) { exportBaseNoteToTXT(baseNote) }) .addItem(Operation(R.string.txt, R.drawable.txt) { exportBaseNoteToTXT(baseNote) })
.addItem(Operation(R.string.xml, R.drawable.xml) { exportBaseNoteToXML(baseNote) })
.addItem(Operation(R.string.html, R.drawable.html) { exportBaseNoteToHTML(baseNote) }) .addItem(Operation(R.string.html, R.drawable.html) { exportBaseNoteToHTML(baseNote) })
.show() .show()
} }
@ -196,7 +195,7 @@ abstract class NotallyFragment : Fragment(), OperationsParent, ItemListener {
} }
override fun onFailure(message: String?) { override fun onFailure(message: String?) {
Toast.makeText(context, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() Toast.makeText(mContext, R.string.something_went_wrong, Toast.LENGTH_SHORT).show()
} }
}) })
} }
@ -208,6 +207,13 @@ abstract class NotallyFragment : Fragment(), OperationsParent, ItemListener {
} }
} }
private fun exportBaseNoteToXML(baseNote: BaseNote) {
lifecycleScope.launch {
val file = model.getXMLFile(baseNote)
showFileOptionsDialog(file, "text/xml")
}
}
private fun exportBaseNoteToHTML(baseNote: BaseNote) { private fun exportBaseNoteToHTML(baseNote: BaseNote) {
lifecycleScope.launch { lifecycleScope.launch {
val file = model.getHTMLFile(baseNote, settingsHelper.getShowDateCreated()) val file = model.getHTMLFile(baseNote, settingsHelper.getShowDateCreated())
@ -227,29 +233,29 @@ abstract class NotallyFragment : Fragment(), OperationsParent, ItemListener {
private fun viewFile(uri: Uri, mimeType: String) { private fun viewFile(uri: Uri, mimeType: String) {
val intent = Intent(Intent.ACTION_VIEW).apply { val intent = Intent(Intent.ACTION_VIEW)
setDataAndType(uri, mimeType) intent.setDataAndType(uri, mimeType)
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
}
val chooser = Intent.createChooser(intent, mContext.getString(R.string.view_note)) val chooser = Intent.createChooser(intent, mContext.getString(R.string.view_note))
startActivity(chooser) startActivity(chooser)
} }
private fun shareFile(uri: Uri, mimeType: String) { private fun shareFile(uri: Uri, mimeType: String) {
val intent = Intent(Intent.ACTION_SEND).apply { val intent = Intent(Intent.ACTION_SEND)
type = mimeType intent.type = mimeType
putExtra(Intent.EXTRA_STREAM, uri) intent.putExtra(Intent.EXTRA_STREAM, uri)
}
val chooser = Intent.createChooser(intent, mContext.getString(R.string.share_note)) val chooser = Intent.createChooser(intent, mContext.getString(R.string.share_note))
startActivity(chooser) startActivity(chooser)
} }
private fun saveFileToDevice(file: File, mimeType: String) { private fun saveFileToDevice(file: File, mimeType: String) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
type = mimeType intent.type = mimeType
addCategory(Intent.CATEGORY_OPENABLE) intent.addCategory(Intent.CATEGORY_OPENABLE)
putExtra(Intent.EXTRA_TITLE, file.nameWithoutExtension) intent.putExtra(Intent.EXTRA_TITLE, file.nameWithoutExtension)
}
model.currentFile = file model.currentFile = file
startActivityForResult(intent, Constants.RequestCodeExportFile) startActivityForResult(intent, Constants.RequestCodeExportFile)
} }

View file

@ -132,6 +132,15 @@ class BaseNoteModel(private val app: Application) : AndroidViewModel(app) {
} }
suspend fun getXMLFile(baseNote: BaseNote) = withContext(Dispatchers.IO) {
val fileName = getFileName(baseNote)
val file = File(getExportedPath(), "$fileName.xml")
val outputStream = FileOutputStream(file)
XMLUtils.writeBaseNoteToStream(baseNote, outputStream)
outputStream.close()
file
}
suspend fun getTXTFile(baseNote: BaseNote, showDateCreated: Boolean) = withContext(Dispatchers.IO) { suspend fun getTXTFile(baseNote: BaseNote, showDateCreated: Boolean) = withContext(Dispatchers.IO) {
val fileName = getFileName(baseNote) val fileName = getFileName(baseNote)
val file = File(getExportedPath(), "$fileName.txt") val file = File(getExportedPath(), "$fileName.txt")
@ -233,6 +242,7 @@ class BaseNoteModel(private val app: Application) : AndroidViewModel(app) {
private fun getHTML(baseNote: BaseNote, showDateCreated: Boolean) = buildString { private fun getHTML(baseNote: BaseNote, showDateCreated: Boolean) = buildString {
val date = formatter.format(baseNote.timestamp) val date = formatter.format(baseNote.timestamp)
append("<!DOCTYPE html>")
append("<html><head><meta charset=\"UTF-8\"></head><body>") append("<html><head><meta charset=\"UTF-8\"></head><body>")
append("<h2>${Html.escapeHtml(baseNote.title)}</h2>") append("<h2>${Html.escapeHtml(baseNote.title)}</h2>")
@ -243,7 +253,7 @@ class BaseNoteModel(private val app: Application) : AndroidViewModel(app) {
when (baseNote.type) { when (baseNote.type) {
Type.NOTE -> { Type.NOTE -> {
val body = baseNote.body.applySpans(baseNote.spans).toHtml() val body = baseNote.body.applySpans(baseNote.spans).toHtml()
append("<p>$body</p>") append(body)
} }
Type.LIST -> { Type.LIST -> {
append("<ol>") append("<ol>")

View file

@ -113,6 +113,22 @@ object XMLUtils {
xmlSerializer.endDocument() xmlSerializer.endDocument()
} }
fun writeBaseNoteToStream(baseNote: BaseNote, stream: OutputStream) {
val xmlSerializer = Xml.newSerializer()
xmlSerializer.setOutput(stream, null)
xmlSerializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true)
xmlSerializer.startDocument("UTF-8", true)
when (baseNote.type) {
Type.NOTE -> appendNote(baseNote, xmlSerializer)
Type.LIST -> appendList(baseNote, xmlSerializer)
}
xmlSerializer.endDocument()
}
private fun appendNote(note: BaseNote, xmlSerializer: XmlSerializer) { private fun appendNote(note: BaseNote, xmlSerializer: XmlSerializer) {
xmlSerializer.startTag(null, XMLTags.Note) xmlSerializer.startTag(null, XMLTags.Note)

View file

@ -5,5 +5,5 @@
android:viewportHeight="24"> android:viewportHeight="24">
<path <path
android:fillColor="#000000" android:fillColor="#000000"
android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z" /> android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2s0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2s0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2s-0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2s-0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z" />
</vector> </vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000000"
android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z" />
</vector>

View file

@ -37,6 +37,7 @@
<string name="export">Export</string> <string name="export">Export</string>
<string name="pdf" translatable="false">PDF</string> <string name="pdf" translatable="false">PDF</string>
<string name="txt" translatable="false">TXT</string> <string name="txt" translatable="false">TXT</string>
<string name="xml" translatable="false">XML</string>
<string name="html" translatable="false">HTML</string> <string name="html" translatable="false">HTML</string>
<string name="save_to_device">Save to device</string> <string name="save_to_device">Save to device</string>
<string name="edit_label">Edit label</string> <string name="edit_label">Edit label</string>

View file

@ -4,7 +4,7 @@ buildscript {
minSdkVersion = 21 minSdkVersion = 21
targetSdkVersion = 30 targetSdkVersion = 30
compileSdkVersion = 30 compileSdkVersion = 30
kotlinVersion = "1.5.10" kotlinVersion = "1.5.21"
buildToolsVersion = "30.0.3" buildToolsVersion = "30.0.3"
} }
@ -14,7 +14,7 @@ buildscript {
} }
dependencies { dependencies {
classpath "com.android.tools.build:gradle:4.2.1" classpath "com.android.tools.build:gradle:4.2.2"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
} }
} }

View file

@ -13,6 +13,7 @@ Add clickable links to notes with support for phone numbers, email addresses and
• PDF • PDF
• TXT • TXT
• XML
• HTML • HTML
<b>Convenience</b> <b>Convenience</b>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 133 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

After

Width:  |  Height:  |  Size: 111 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Before After
Before After