@@ -100,6 +100,19 @@ class SettingsActivity : ComponentActivity(), SharedPreferences.OnSharedPreferen
100100 uri?.let { performClipboardImport(it) }
101101 }
102102
103+ // SAF file pickers for swipe ML data export
104+ private val swipeDataJsonExportLauncher = registerForActivityResult(
105+ ActivityResultContracts .CreateDocument (" application/json" )
106+ ) { uri: Uri ? ->
107+ uri?.let { performSwipeDataJsonExport(it) }
108+ }
109+
110+ private val swipeDataNdjsonExportLauncher = registerForActivityResult(
111+ ActivityResultContracts .CreateDocument (" application/x-ndjson" )
112+ ) { uri: Uri ? ->
113+ uri?.let { performSwipeDataNdjsonExport(it) }
114+ }
115+
103116 // Settings state for reactive UI
104117 private var beamWidth by mutableStateOf(6 )
105118 private var maxLength by mutableStateOf(20 )
@@ -3448,15 +3461,37 @@ class SettingsActivity : ComponentActivity(), SharedPreferences.OnSharedPreferen
34483461 }
34493462
34503463 private fun exportSwipeDataJSON () {
3464+ try {
3465+ val sdf = java.text.SimpleDateFormat (" yyyyMMdd_HHmmss" , java.util.Locale .US )
3466+ val filename = " swipe_data_${sdf.format(java.util.Date ())} .json"
3467+ swipeDataJsonExportLauncher.launch(filename)
3468+ } catch (e: Exception ) {
3469+ Toast .makeText(this , " Could not open file picker: ${e.message} " , Toast .LENGTH_SHORT ).show()
3470+ }
3471+ }
3472+
3473+ private fun exportSwipeDataNDJSON () {
3474+ try {
3475+ val sdf = java.text.SimpleDateFormat (" yyyyMMdd_HHmmss" , java.util.Locale .US )
3476+ val filename = " swipe_data_${sdf.format(java.util.Date ())} .ndjson"
3477+ swipeDataNdjsonExportLauncher.launch(filename)
3478+ } catch (e: Exception ) {
3479+ Toast .makeText(this , " Could not open file picker: ${e.message} " , Toast .LENGTH_SHORT ).show()
3480+ }
3481+ }
3482+
3483+ private fun performSwipeDataJsonExport (uri : Uri ) {
34513484 lifecycleScope.launch {
34523485 try {
3453- val dataStore = tribixbite.cleverkeys.ml.SwipeMLDataStore .getInstance(this @SettingsActivity)
3454- val exportFile = dataStore.exportToJSON()
3455- Toast .makeText(
3456- this @SettingsActivity,
3457- " Exported to: ${exportFile.absolutePath} " ,
3458- Toast .LENGTH_LONG
3459- ).show()
3486+ contentResolver.openOutputStream(uri)?.use { outputStream ->
3487+ val dataStore = tribixbite.cleverkeys.ml.SwipeMLDataStore .getInstance(this @SettingsActivity)
3488+ val count = dataStore.exportToJSON(outputStream)
3489+ Toast .makeText(
3490+ this @SettingsActivity,
3491+ " Exported $count swipe entries to JSON" ,
3492+ Toast .LENGTH_SHORT
3493+ ).show()
3494+ } ? : throw Exception (" Could not open file for writing" )
34603495 } catch (e: Exception ) {
34613496 Toast .makeText(
34623497 this @SettingsActivity,
@@ -3467,16 +3502,18 @@ class SettingsActivity : ComponentActivity(), SharedPreferences.OnSharedPreferen
34673502 }
34683503 }
34693504
3470- private fun exportSwipeDataNDJSON ( ) {
3505+ private fun performSwipeDataNdjsonExport ( uri : Uri ) {
34713506 lifecycleScope.launch {
34723507 try {
3473- val dataStore = tribixbite.cleverkeys.ml.SwipeMLDataStore .getInstance(this @SettingsActivity)
3474- val exportFile = dataStore.exportToNDJSON()
3475- Toast .makeText(
3476- this @SettingsActivity,
3477- " Exported to: ${exportFile.absolutePath} " ,
3478- Toast .LENGTH_LONG
3479- ).show()
3508+ contentResolver.openOutputStream(uri)?.use { outputStream ->
3509+ val dataStore = tribixbite.cleverkeys.ml.SwipeMLDataStore .getInstance(this @SettingsActivity)
3510+ val count = dataStore.exportToNDJSON(outputStream)
3511+ Toast .makeText(
3512+ this @SettingsActivity,
3513+ " Exported $count swipe entries to NDJSON" ,
3514+ Toast .LENGTH_SHORT
3515+ ).show()
3516+ } ? : throw Exception (" Could not open file for writing" )
34803517 } catch (e: Exception ) {
34813518 Toast .makeText(
34823519 this @SettingsActivity,
0 commit comments