Skip to content

Commit 964ab18

Browse files
authored
Merge pull request #13 from j-almenara-r/copilot/fix-export-to-markdown-feature
Replace direct file access with Storage Access Framework for markdown export
2 parents 419bbf9 + b588830 commit 964ab18

3 files changed

Lines changed: 47 additions & 29 deletions

File tree

app/src/main/AndroidManifest.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
<uses-permission android:name="android.permission.RECORD_AUDIO" />
55
<uses-permission android:name="android.permission.INTERNET" />
6-
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
7-
android:maxSdkVersion="28" />
86

97
<uses-feature
108
android:name="android.hardware.type.automotive"

app/src/main/java/com/voicenotes/MainActivity.kt

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ package com.voicenotes
33
import android.Manifest
44
import android.content.Intent
55
import android.content.pm.PackageManager
6+
import android.net.Uri
67
import android.os.Bundle
7-
import android.os.Environment
88
import android.speech.RecognizerIntent
99
import android.speech.SpeechRecognizer
1010
import android.widget.Button
@@ -13,8 +13,6 @@ import android.widget.Toast
1313
import androidx.appcompat.app.AppCompatActivity
1414
import androidx.core.app.ActivityCompat
1515
import androidx.core.content.ContextCompat
16-
import java.io.File
17-
import java.io.FileWriter
1816
import java.text.SimpleDateFormat
1917
import java.time.LocalDateTime
2018
import java.time.format.DateTimeFormatter
@@ -27,6 +25,7 @@ class MainActivity : AppCompatActivity() {
2725
private lateinit var notesTextView: TextView
2826
private val RECORD_AUDIO_PERMISSION_CODE = 1
2927
private val SPEECH_REQUEST_CODE = 0
28+
private val CREATE_FILE_REQUEST_CODE = 2
3029

3130
companion object {
3231
private const val ISO_8601_FILENAME_PATTERN = "yyyy-MM-dd'T'HH-mm-ss"
@@ -113,6 +112,10 @@ class MainActivity : AppCompatActivity() {
113112
}
114113
notesTextView.text = newText
115114
}
115+
} else if (requestCode == CREATE_FILE_REQUEST_CODE && resultCode == RESULT_OK) {
116+
data?.data?.let { uri ->
117+
writeNotesToUri(uri)
118+
}
116119
}
117120
}
118121

@@ -146,45 +149,61 @@ class MainActivity : AppCompatActivity() {
146149
return
147150
}
148151

152+
// Generate ISO 8601 timestamp for filename (filename-safe format)
153+
val filenameTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
154+
LocalDateTime.now().format(DateTimeFormatter.ofPattern(ISO_8601_FILENAME_PATTERN))
155+
} else {
156+
SimpleDateFormat(ISO_8601_FILENAME_PATTERN, Locale.getDefault()).format(Date())
157+
}
158+
159+
// Use Storage Access Framework to let user choose location
160+
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
161+
addCategory(Intent.CATEGORY_OPENABLE)
162+
type = "text/markdown"
163+
putExtra(Intent.EXTRA_TITLE, "voice-notes-$filenameTimestamp.md")
164+
}
165+
166+
try {
167+
startActivityForResult(intent, CREATE_FILE_REQUEST_CODE)
168+
} catch (e: Exception) {
169+
Toast.makeText(
170+
this,
171+
getString(R.string.export_error, e.message),
172+
Toast.LENGTH_LONG
173+
).show()
174+
}
175+
}
176+
177+
private fun writeNotesToUri(uri: Uri) {
178+
val currentText = notesTextView.text.toString()
179+
149180
try {
150-
// Generate ISO 8601 timestamp for filename (filename-safe format)
151-
val filenameTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
152-
LocalDateTime.now().format(DateTimeFormatter.ofPattern(ISO_8601_FILENAME_PATTERN))
153-
} else {
154-
SimpleDateFormat(ISO_8601_FILENAME_PATTERN, Locale.getDefault()).format(Date())
155-
}
156-
157181
// Generate human-readable timestamp for content
158182
val readableTimestamp = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
159183
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
160184
} else {
161185
SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Date())
162186
}
163187

164-
// Create VoiceNotes directory in Documents
165-
val documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
166-
val voiceNotesDir = File(documentsDir, "VoiceNotes")
167-
168-
if (!voiceNotesDir.exists()) {
169-
voiceNotesDir.mkdirs()
188+
// Build the complete markdown content
189+
val markdownContent = buildString {
190+
append("# Voice Notes Export\n\n")
191+
append("**Exported on:** $readableTimestamp\n\n")
192+
append("---\n\n")
193+
append(currentText)
194+
append("\n")
170195
}
171196

172-
// Create the markdown file
173-
val filename = "voice-notes-$filenameTimestamp.md"
174-
val file = File(voiceNotesDir, filename)
175-
176197
// Write content to the file with markdown formatting
177-
FileWriter(file).use { writer ->
178-
writer.write("# Voice Notes Export\n\n")
179-
writer.write("**Exported on:** $readableTimestamp\n\n")
180-
writer.write("---\n\n")
181-
writer.write(currentText)
182-
writer.write("\n")
198+
contentResolver.openOutputStream(uri)?.use { outputStream ->
199+
outputStream.write(markdownContent.toByteArray())
200+
} ?: run {
201+
throw Exception("Failed to open output stream")
183202
}
184203

185204
Toast.makeText(
186205
this,
187-
getString(R.string.export_success, file.absolutePath),
206+
getString(R.string.export_success_new),
188207
Toast.LENGTH_LONG
189208
).show()
190209

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<string name="title_text">Voice Notes</string>
77
<string name="export_button_text">📄 Export to Markdown</string>
88
<string name="export_success">Notes exported successfully to: %1$s</string>
9+
<string name="export_success_new">Notes exported successfully! Check your chosen location.</string>
910
<string name="export_error">Failed to export notes: %1$s</string>
1011
<string name="export_no_notes">No notes to export</string>
1112
</resources>

0 commit comments

Comments
 (0)