fix(recordings): open folder with android picker
Build & Deploy Pluriwave / Análisis de código (push) Successful in 24s
Build & Deploy Pluriwave / Build APK + AAB release (push) Failing after 1m0s

This commit is contained in:
2026-05-22 18:24:05 +02:00
parent 6a5fcd8d96
commit 9ad58898e0
2 changed files with 66 additions and 0 deletions
@@ -1,12 +1,16 @@
package es.freetimelab.pluriwave package es.freetimelab.pluriwave
import android.Manifest import android.Manifest
import android.app.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.net.Uri
import android.media.audiofx.Visualizer import android.media.audiofx.Visualizer
import android.os.Build import android.os.Build
import android.os.Environment
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.DocumentsContract
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.ryanheise.audioservice.AudioServiceActivity import com.ryanheise.audioservice.AudioServiceActivity
import io.flutter.embedding.engine.FlutterEngine import io.flutter.embedding.engine.FlutterEngine
@@ -16,6 +20,7 @@ import io.flutter.plugin.common.MethodChannel
class MainActivity : AudioServiceActivity() { class MainActivity : AudioServiceActivity() {
private val visualizerChannel = "pluriwave/audio_visualizer" private val visualizerChannel = "pluriwave/audio_visualizer"
private val alarmChannel = "pluriwave/alarm_scheduler" private val alarmChannel = "pluriwave/alarm_scheduler"
private val fileActionsChannel = "pluriwave/file_actions"
private val permissionRequestCode = 4821 private val permissionRequestCode = 4821
private var visualizer: Visualizer? = null private var visualizer: Visualizer? = null
private var pendingSink: EventChannel.EventSink? = null private var pendingSink: EventChannel.EventSink? = null
@@ -96,6 +101,23 @@ class MainActivity : AudioServiceActivity() {
else -> result.notImplemented() else -> result.notImplemented()
} }
} }
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
fileActionsChannel
).setMethodCallHandler { call, result ->
when (call.method) {
"openDirectory" -> {
val path = call.argument<String>("path")
if (path.isNullOrBlank()) {
result.success(false)
} else {
result.success(openDirectory(path))
}
}
else -> result.notImplemented()
}
}
} }
override fun onNewIntent(intent: Intent) { override fun onNewIntent(intent: Intent) {
@@ -122,6 +144,38 @@ class MainActivity : AudioServiceActivity() {
) )
} }
private fun openDirectory(path: String): Boolean {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
addFlags(
Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_WRITE_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
)
directoryTreeUri(path)?.let { putExtra(DocumentsContract.EXTRA_INITIAL_URI, it) }
}
return try {
startActivity(intent)
true
} catch (_: ActivityNotFoundException) {
false
} catch (_: Throwable) {
false
}
}
private fun directoryTreeUri(path: String): Uri? {
val external = Environment.getExternalStorageDirectory()?.absolutePath ?: return null
if (!path.startsWith(external)) return null
val relative = path.removePrefix(external).trimStart('/')
val documentId = if (relative.isBlank()) "primary:" else "primary:$relative"
return DocumentsContract.buildTreeDocumentUri(
"com.android.externalstorage.documents",
documentId
)
}
private fun startVisualizerWhenAllowed() { private fun startVisualizerWhenAllowed() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(Manifest.permission.RECORD_AUDIO) checkSelfPermission(Manifest.permission.RECORD_AUDIO)
+12
View File
@@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:geocoding/geocoding.dart'; import 'package:geocoding/geocoding.dart';
import 'package:geolocator/geolocator.dart'; import 'package:geolocator/geolocator.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
@@ -23,6 +24,10 @@ enum OrdenEmisoras { nombre, calidad }
/// Estado global de la app con ChangeNotifier (Provider). /// Estado global de la app con ChangeNotifier (Provider).
class EstadoRadio extends ChangeNotifier { class EstadoRadio extends ChangeNotifier {
static const MethodChannel _fileActionsChannel = MethodChannel(
'pluriwave/file_actions',
);
EstadoRadio({ EstadoRadio({
ServicioAudio? audio, ServicioAudio? audio,
ServicioFavoritos? favoritos, ServicioFavoritos? favoritos,
@@ -626,6 +631,13 @@ class EstadoRadio extends ChangeNotifier {
Future<bool> abrirDirectorioGrabacion() async { Future<bool> abrirDirectorioGrabacion() async {
final ruta = await directorioGrabacionEfectivo(); final ruta = await directorioGrabacionEfectivo();
await Directory(ruta).create(recursive: true); await Directory(ruta).create(recursive: true);
if (!kIsWeb && Platform.isAndroid) {
final abierto = await _fileActionsChannel.invokeMethod<bool>(
'openDirectory',
{'path': ruta},
);
return abierto ?? false;
}
final uri = Uri.directory(ruta); final uri = Uri.directory(ruta);
return launchUrl(uri, mode: LaunchMode.externalApplication); return launchUrl(uri, mode: LaunchMode.externalApplication);
} }