Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />

<application
android:allowBackup="true"
Expand Down
73 changes: 46 additions & 27 deletions app/src/main/java/com/voicenotes/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.voicenotes
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer
import android.widget.Button
Expand All @@ -13,8 +13,6 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import java.io.File
import java.io.FileWriter
import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
Expand All @@ -27,6 +25,7 @@ class MainActivity : AppCompatActivity() {
private lateinit var notesTextView: TextView
private val RECORD_AUDIO_PERMISSION_CODE = 1
private val SPEECH_REQUEST_CODE = 0
private val CREATE_FILE_REQUEST_CODE = 2

companion object {
private const val ISO_8601_FILENAME_PATTERN = "yyyy-MM-dd'T'HH-mm-ss"
Expand Down Expand Up @@ -113,6 +112,10 @@ class MainActivity : AppCompatActivity() {
}
notesTextView.text = newText
}
} else if (requestCode == CREATE_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
data?.data?.let { uri ->
writeNotesToUri(uri)
}
}
}

Expand Down Expand Up @@ -146,45 +149,61 @@ class MainActivity : AppCompatActivity() {
return
}

// Generate ISO 8601 timestamp for filename (filename-safe format)
val filenameTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
LocalDateTime.now().format(DateTimeFormatter.ofPattern(ISO_8601_FILENAME_PATTERN))
} else {
SimpleDateFormat(ISO_8601_FILENAME_PATTERN, Locale.getDefault()).format(Date())
}

// Use Storage Access Framework to let user choose location
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/markdown"
putExtra(Intent.EXTRA_TITLE, "voice-notes-$filenameTimestamp.md")
}

try {
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE)
} catch (e: Exception) {
Toast.makeText(
this,
getString(R.string.export_error, e.message),
Toast.LENGTH_LONG
).show()
}
}

private fun writeNotesToUri(uri: Uri) {
val currentText = notesTextView.text.toString()

try {
// Generate ISO 8601 timestamp for filename (filename-safe format)
val filenameTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
LocalDateTime.now().format(DateTimeFormatter.ofPattern(ISO_8601_FILENAME_PATTERN))
} else {
SimpleDateFormat(ISO_8601_FILENAME_PATTERN, Locale.getDefault()).format(Date())
}

// Generate human-readable timestamp for content
val readableTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
} else {
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
}

// Create VoiceNotes directory in Documents
val documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
val voiceNotesDir = File(documentsDir, "VoiceNotes")

if (!voiceNotesDir.exists()) {
voiceNotesDir.mkdirs()
// Build the complete markdown content
val markdownContent = buildString {
append("# Voice Notes Export\n\n")
append("**Exported on:** $readableTimestamp\n\n")
append("---\n\n")
append(currentText)
append("\n")
}

// Create the markdown file
val filename = "voice-notes-$filenameTimestamp.md"
val file = File(voiceNotesDir, filename)

// Write content to the file with markdown formatting
FileWriter(file).use { writer ->
writer.write("# Voice Notes Export\n\n")
writer.write("**Exported on:** $readableTimestamp\n\n")
writer.write("---\n\n")
writer.write(currentText)
writer.write("\n")
contentResolver.openOutputStream(uri)?.use { outputStream ->
outputStream.write(markdownContent.toByteArray())
} ?: run {
throw Exception("Failed to open output stream")
}

Toast.makeText(
this,
getString(R.string.export_success, file.absolutePath),
getString(R.string.export_success_new),
Toast.LENGTH_LONG
).show()

Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<string name="title_text">Voice Notes</string>
<string name="export_button_text">📄 Export to Markdown</string>
<string name="export_success">Notes exported successfully to: %1$s</string>
<string name="export_success_new">Notes exported successfully! Check your chosen location.</string>
<string name="export_error">Failed to export notes: %1$s</string>
<string name="export_no_notes">No notes to export</string>
</resources>