ali
ali

Reputation: 969

Select image for flutter web on mobile device

Im currently using https://pub.dev/packages/file_picker for this function

FilePickerResult result =
    await FilePicker.platform.pickFiles();

if (result != null) {
  setState(() {
    filePicked = result;
  });

for (int i = 0; i < result.files.length; i++) {
    setState(() {
      listBytes.add(result.files[i].bytes);
    });
  }
} else {
  // User canceled the picker
}

when i test on web it work successfully, however the problem occur when running on web app (in mobile) after select image it got no respond. It's hard to debug since i don't really know on how to debug for web app. My question is, can i just use the function i use on web, or is there any specific function i need to use in order for it to work in web app.

Upvotes: 1

Views: 849

Answers (1)

dreambit.io dreambitio
dreambit.io dreambitio

Reputation: 1902

You can try this for the web app (This method should only be used for the web platform):

import '../../models/html_nonweb.dart'
    if (dart.library.js) 'dart:html' as html;

  Future<WebFileModel> pickWebFileModel() {
    final completer = Completer<WebFileModel>();
    final html.InputElement input =
        html.document.createElement('input') as html.InputElement;
    input
      ..type = 'file'
      ..accept = 'image/*';
    input.onChange.listen((e) async {
      final List<html.File> files = input.files!;
      final reader = html.FileReader();
      reader.readAsDataUrl(files.first);
      reader.onError.listen(completer.completeError);
      final Future<WebFileModel> resultsFutures =
          reader.onLoad.first.then((_) => WebFileModel(
                path: reader.result! as String,
                type: files.first.type as String,
                createdAt: DateTime.fromMillisecondsSinceEpoch(
                  files.first.lastModified!,
                ),
                htmlFile: files.first,
              ));
      final results = await resultsFutures;
      completer.complete(results);
    });
    input.click();
    return completer.future;
  }

To use this code, you need to create the html_nonweb.dart file:

const document = Document();

class Document {
  const Document();

  Element createElement(String el) => InputElement();
}

class File {
  final int? lastModified = null;

  final String? type = null;
}

class Element {
  const Element();
}

class InputElement extends Element {
  const InputElement();

  final List<File>? files = null;

  Stream<Object> get onChange => Stream.empty();

  set type(String type) {}

  set multiple(bool multiple) {}

  set accept(String s) {}

  void readAsDataUrl(File file) {}

  void click() {}
}

class FileReader {
  Stream<void Function(Object error, [StackTrace? stackTrace])> get onError =>
      Stream.empty();

  void readAsDataUrl(File file) {}

  Stream<Object> get onLoad => Stream.empty();

  final Object? result = null;
}

And WebFileModel:

import 'dart:typed_data';

import 'html_nonweb.dart' if (dart.library.js) 'dart:html' as html;

class WebFileModel {
  final String path;
  final String type;
  final DateTime createdAt;
  final html.File? htmlFile;
  final Uint8List? uIntFile;

  WebFileModel({
    required this.path,
    required this.type,
    required this.createdAt,
    this.htmlFile,
    this.uIntFile,
  });

  WebFileModel copyWith({
    String? path,
    String? type,
    DateTime? createdAt,
    html.File? htmlFile,
    Uint8List? uIntFile,
  }) {
    return WebFileModel(
      path: path ?? this.path,
      type: type ?? this.type,
      createdAt: createdAt ?? this.createdAt,
      htmlFile: htmlFile ?? this.htmlFile,
      uIntFile: uIntFile ?? this.uIntFile,
    );
  }
}

To get a Uint8List, you need to do the following:

final imageBase64 =media.path.replaceFirst(RegExp(r'data:image/[^;]+;base64,'), '');
final uIntFile = base64Decode(imageBase64);

Upvotes: 1

Related Questions