saf_stream 0.10.0 copy "saf_stream: ^0.10.0" to clipboard
saf_stream: ^0.10.0 copied to clipboard

PlatformAndroid

Read and write Android SAF `DocumentFile`.

example/lib/main.dart

import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:saf_stream/saf_stream.dart';
import 'package:saf_util/saf_util.dart';
import 'package:saf_util/saf_util_platform_interface.dart';
import 'package:tmp_path/tmp_path.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _safUtil = SafUtil();
  final _safStreamPlugin = SafStream();
  List<SafDocumentFile> _files = [];
  String? _treeUri;
  String _output = '';
  int _session = 0;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: SingleChildScrollView(
          child: Container(
            padding: const EdgeInsets.all(10),
            child: _treeUri == null
                ? OutlinedButton(
                    onPressed: _selectFolder,
                    child: const Text('Select a folder'))
                : Column(
                    children: [
                      Text(_output),
                      _sep(),
                      OutlinedButton(
                          onPressed: _reload, child: const Text('Reload')),
                      OutlinedButton(
                          onPressed: () => _writeFile(null, false),
                          child: const Text('Create a new random file')),
                      OutlinedButton(
                          onPressed: () => _writeFile('1.txt', false),
                          child: const Text('Create 1.txt')),
                      OutlinedButton(
                          onPressed: () => _writeFile('1.txt', true),
                          child: const Text('Create 1.txt (overwrite)')),
                      OutlinedButton(
                          onPressed: () => _pasteLocalFile(false),
                          child: const Text(
                              'Create a.bin from local file (pasteLocalFile)')),
                      OutlinedButton(
                          onPressed: () => _pasteLocalFile(true),
                          child: const Text(
                              'Create a.bin from local file (pasteLocalFile) (overwrite)')),
                      OutlinedButton(
                          onPressed: () => _writeFileBytes(false),
                          child: const Text('Write a.bin bytes')),
                      OutlinedButton(
                          onPressed: () => _writeFileBytes(true),
                          child: const Text('Write a.bin bytes (overwrite)')),
                      ...(_files.where((f) => !f.isDir == true).map((f) =>
                          Container(
                            padding: const EdgeInsets.all(8),
                            decoration: BoxDecoration(
                                border: Border.all(color: Colors.grey)),
                            child: Column(
                              children: [
                                Text(f.name),
                                _sep(),
                                OutlinedButton(
                                    onPressed: () => _readFileStream(f.uri),
                                    child: const Text('Read stream')),
                                _sep(),
                                OutlinedButton(
                                    onPressed: () => _readFileBytes(f.uri),
                                    child: const Text('Read bytes')),
                                _sep(),
                                OutlinedButton(
                                    onPressed: () => _copyToLocalFile(f.uri),
                                    child: const Text('Copy to local file')),
                              ],
                            ),
                          ))),
                      const SizedBox(width: 10),
                    ],
                  ),
          ),
        ),
      ),
    );
  }

  Widget _sep() {
    return const SizedBox(width: 10);
  }

  Future<void> _reload() async {
    try {
      if (_treeUri == null) {
        return;
      }
      var files = await _safUtil.list(_treeUri!);
      setState(() {
        _files = files;
        _output = '';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _selectFolder() async {
    try {
      var treeUri = await _safUtil.openDirectory();
      if (treeUri == null) {
        return;
      }
      _treeUri = treeUri;
      await _reload();
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _readFileStream(String uri) async {
    try {
      _clearOutput();
      var session = ++_session;
      await for (var bytes in await _safStreamPlugin.readFileStream(uri,
          bufferSize: 500 * 1024)) {
        setState(() {
          _output += '$session - <Bytes:${bytes.length}>\n';
        });
      }
      setState(() {
        _output += '$session - <Done>\n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _readFileBytes(String uri) async {
    try {
      _clearOutput();
      var session = ++_session;
      final bytes = await _safStreamPlugin.readFileBytes(uri);
      setState(() {
        _output += '$session - Bytes: ${bytes.lengthInBytes} \n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  void _clearOutput() {
    setState(() {
      _output = '';
    });
  }

  Future<void> _copyToLocalFile(String uri) async {
    try {
      _clearOutput();
      final dest = tmpPath();
      await _safStreamPlugin.copyToLocalFile(uri, dest);
      final localContents = await File(dest).readAsBytes();
      setState(() {
        _output += 'Local contents:\n$localContents\n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _writeFile(String? fileName, bool overwrite) async {
    try {
      _clearOutput();
      var treeUri = _treeUri;
      if (treeUri == null) {
        return;
      }
      var session = ++_session;
      fileName = fileName ?? DateTime.now().millisecondsSinceEpoch.toString();

      var info = await _safStreamPlugin.startWriteStream(
          treeUri, fileName, 'text/plain',
          overwrite: overwrite);
      setState(() {
        _output += '$session - <Writing file $info>\n';
      });
      for (var i = 0; i < 3; i++) {
        setState(() {
          _output += '$session - <Writing chunk ${i + 1}>\n';
        });
        await _safStreamPlugin.writeChunk(
            info.session, utf8.encode(i.toString()));
        await Future<void>.delayed(const Duration(seconds: 1));
      }
      await _safStreamPlugin.endWriteStream(info.session);
      setState(() {
        _output += '$session - <Finished writing $info>\n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _pasteLocalFile(bool overwrite) async {
    try {
      _clearOutput();
      var treeUri = _treeUri;
      if (treeUri == null) {
        return;
      }

      final localSrc = tmpPath();
      await File(localSrc).writeAsString('✅❌❤️⚒️😊😒');

      final info = await _safStreamPlugin.pasteLocalFile(
          localSrc, treeUri, 'a.bin', 'application/octet-stream',
          overwrite: overwrite);
      setState(() {
        _output = 'Created file: $info\n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }

  Future<void> _writeFileBytes(bool overwrite) async {
    try {
      _clearOutput();
      var treeUri = _treeUri;
      if (treeUri == null) {
        return;
      }

      final info = await _safStreamPlugin.writeFileBytes(
          treeUri,
          'a.bin',
          'application/octet-stream',
          Uint8List.fromList(utf8.encode('✅❌❤️⚒️😊😒')),
          overwrite: overwrite);
      setState(() {
        _output = 'Created file: $info\n';
      });
    } catch (err) {
      setState(() {
        _output = err.toString();
      });
    }
  }
}
5
likes
150
points
1.83k
downloads

Publisher

verified publisherflutter-cavalry.com

Weekly Downloads

Read and write Android SAF `DocumentFile`.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on saf_stream