uploadcare_client 1.0.1

  • Readme
  • Changelog
  • Example
  • Installing
  • new50

Flutter Uploadcare Client #

Introduction #

Uploadcare is a complete file handling platform that helps you ship products faster and focus on your business goals, not files. With Uploadcare, you can build an infrastructure, optimize content, conversions, load times, traffic, and user experience. Read more...

Implemented features: #

  • authorization
  • upload, read more
    • base
    • multipart
    • from url
    • signed uploads, read more
  • files API, read more
    • get one file
    • get list of files
    • remove multiple files
    • store multiple files
  • groups API
    • get one group
    • get list of groups
    • create group
    • store all files in group
  • video encoding, read more
    • create processing tasks
    • retrieve processing status
  • CDN API
  • Flutter (mobile/web)
    • UploadcareImageProvider

Roadmap: #

  • document conversion
  • complete transformations API (overlays, gif to video, .etc)
  • write more tests
  • more informative example
  • test on web
  • improve documentation

Example: #

Note: you can omit privateKey, but in this case only Upload API will be available. (CDN API also will be available).

How to use library:

// create client with simple auth scheme
final client = UploadcareClient.withSimpleAuth(
  publicKey: 'UPLOADCARE_PUBLIC_KEY',
  privateKey: 'UPLOADCARE_PRIVATE_KEY',
  apiVersion: 'v0.5',
);
// or create client with reqular auth scheme
final client = UploadcareClient.withRegularAuth(
  publicKey: 'UPLOADCARE_PUBLIC_KEY',
  privateKey: 'UPLOADCARE_PRIVATE_KEY',
  apiVersion: 'v0.5',
);
// or more flexible
final client = UploadcareClient(
  options: ClientOptions(
    authorizationScheme: AuthSchemeRegular(
      apiVersion: 'v0.5',
      publicKey: 'UPLOADCARE_PUBLIC_KEY',
      privateKey: 'UPLOADCARE_PRIVATE_KEY',
    ),
    // rest options...
  ),
);

UploadcareClient has at the moment 4 API section

final ApiUpload upload;
final ApiFiles files;
final ApiVideoEncoding videoEncoding;
final ApiGroups groups;

You can use each api section separately, for example:

final options = ClientOptions(
  authorizationScheme: AuthSchemeRegular(
    apiVersion: 'v0.5',
    publicKey: 'UPLOADCARE_PUBLIC_KEY',
    privateKey: 'UPLOADCARE_PRIVATE_KEY',
  )
);

final upload = ApiUpload(options: options);
final fileId = await upload.base(File('...some/file'));
// ...etc.

The library provides UploadcareImageProvider for more effective use in the widget ecosystem, how to use image provider:

Image(
  image: UploadcareImageProvider(
    'uploadcare-image-file-uuid',
    // optional, apply transformations to the image
    transformations: [
      BlurTransformation(50),
      GrayscaleTransformation(),
      InvertTransformation(),
      ImageResizeTransformation(Size.square(58))
    ],
    // rest image props...
  ),
)

[1.0.0] - Thu Sep 26 2019

  • Move to stable version

[0.0.1] - Thu Sep 26 2019

  • Initial release

example/README.md

flutter_uploadcare_client_example #

import 'dart:async';
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:image_picker/image_picker.dart';
import 'package:uploadcare_client/uploadcare_client.dart';

void main() async {
  await DotEnv().load('.env');

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter uploadcare client example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter uploadcare client example'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _Item {
  final FileInfoEntity fileInfo;
  final VideoEncodingJobEntity encoding;
  final ProgressEntity progress;

  const _Item({
    this.fileInfo,
    this.encoding,
    this.progress,
  });

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is _Item &&
          runtimeType == other.runtimeType &&
          fileInfo == other.fileInfo &&
          encoding == other.encoding &&
          progress == other.progress;

  @override
  int get hashCode => fileInfo.hashCode ^ encoding.hashCode ^ progress.hashCode;
}

class _MyHomePageState extends State<MyHomePage> {
  List<_Item> _files;
  StreamController<List<_Item>> _controller;
  UploadcareClient _client;

  @override
  void initState() {
    super.initState();

    _files = [];

    _client = UploadcareClient.withSimpleAuth(
      publicKey: DotEnv().env['UPLOADCARE_PUBLIC_KEY'],
      privateKey: DotEnv().env['UPLOADCARE_PRIVATE_KEY'],
      apiVersion: 'v0.5',
    );

    _controller = StreamController.broadcast();

    WidgetsBinding.instance.addPostFrameCallback((_) => _client.files
            .list(
                limit: 500,
                stored: false,
                removed: false,
                ordering: FilesOrdering(
                  FilesFilterValue.DatetimeUploaded,
                  direction: OrderDirection.Desc,
                ))
            .then((value) {
          _files.addAll(
              value.results.map((item) => _Item(fileInfo: item)).toList());

          _controller.add(_files);
        }));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: StreamBuilder(
        stream: _controller.stream,
        initialData: null,
        builder: (BuildContext context, AsyncSnapshot<List<_Item>> snapshot) {
          if (!snapshot.hasData)
            return Center(
              child: CircularProgressIndicator(),
            );

          final files = snapshot.data;

          return ListView.separated(
            separatorBuilder: (context, index) => SizedBox(
              height: 5,
            ),
            itemCount: files.length,
            itemBuilder: (context, index) => MediaListItem(
              fileInfo: files[index].fileInfo,
              progress: files[index].progress,
              encoding: files[index].encoding,
            ),
          );
        },
      ),
      floatingActionButton: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          FloatingActionButton(
            mini: true,
            child: Icon(Icons.image),
            onPressed: () async {
              final file =
                  await ImagePicker.pickImage(source: ImageSource.gallery);

              if (file == null) return;

              _upload(file);
            },
          ),
          SizedBox(
            height: 10,
          ),
          FloatingActionButton(
            mini: true,
            child: Icon(Icons.camera),
            onPressed: () async {
              final file =
                  await ImagePicker.pickVideo(source: ImageSource.camera);

              if (file == null) return;

              _upload(file);
            },
          ),
        ],
      ),
    );
  }

  Future _upload(File file) async {
    _files.insert(
      0,
      _Item(
        progress: ProgressEntity(0, await file.length()),
      ),
    );

    _controller.add(_files);

    final fileId = await _client.upload.auto(
      file,
      storeMode: false,
      onProgress: (value) {
        _files[0] = _Item(progress: value);
        _controller.add(_files);
      },
    );

    final fileInfo = await _client.files.file(fileId);

    if (!fileInfo.isImage) {
      final videoTransformations = [
        CutTransformation(const Duration(seconds: 0),
            length: const Duration(seconds: 10)),
        VideoThumbsGenerateTransformation(5),
      ];
      final result =
          await _client.videoEncoding.process({fileId: videoTransformations});

      if (result.problems.isEmpty) {
        final stream =
            _client.videoEncoding.statusAsStream(result.results.first.token);
        await for (VideoEncodingJobEntity job in stream) {
          _files[0] = _Item(
            fileInfo: fileInfo,
            encoding: job,
          );
          _controller.add(_files);
        }
      } else {
        _files[0] = _Item(
          fileInfo: fileInfo,
          encoding: VideoEncodingJobEntity(
            errorMessage: result.problems.values.first,
            status: VideoEncodingJobStatusValue.Failed,
          ),
        );
        _controller.add(_files);
      }
    }

    _files[0] = _Item(
      fileInfo: fileInfo,
    );

    _controller.add(_files);
  }
}

class MediaListItem extends StatelessWidget {
  MediaListItem({
    Key key,
    this.fileInfo,
    this.progress,
    this.encoding,
  }) : super(key: key);

  final FileInfoEntity fileInfo;
  final ProgressEntity progress;
  final VideoEncodingJobEntity encoding;

  bool get _isUploaded => fileInfo != null;

  Widget _buildEncoding() {
    if (encoding.status == VideoEncodingJobStatusValue.Failed)
      return Text(
        encoding.errorMessage,
        style: TextStyle(
          color: Colors.redAccent,
        ),
      );
    if (encoding.status == VideoEncodingJobStatusValue.Processing ||
        encoding.status == VideoEncodingJobStatusValue.Pending)
      return Text('encoding...');
    if (encoding.status == VideoEncodingJobStatusValue.Finished)
      return Text(fileInfo.filename);

    return Text('getting status...');
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          if (!_isUploaded)
            Center(
              child: LinearProgressIndicator(
                value: progress?.value == 1 ? null : progress?.value ?? null,
              ),
            ),
          if (_isUploaded)
            ListTile(
              contentPadding: const EdgeInsets.all(10.0),
              leading: fileInfo.isImage
                  ? Image(
                      height: 58,
                      width: 58,
                      fit: BoxFit.contain,
                      image: UploadcareImageProvider(
                        fileInfo.id,
                        transformations: [
                          BlurTransformation(50),
                          GrayscaleTransformation(),
                          InvertTransformation(),
                          ImageResizeTransformation(Size.square(58))
                        ],
                      ),
                    )
                  : Container(
                      height: 58,
                      width: 58,
                      child: Center(
                        child: Icon(Icons.video_library),
                      ),
                    ),
              title: _isUploaded && encoding == null
                  ? Text(fileInfo?.filename ?? 'preparing...')
                  : _buildEncoding(),
            ),
        ],
      ),
    );
  }
}

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  uploadcare_client: ^1.0.1

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:uploadcare_client/uploadcare_client.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100
Overall:
Weighted score of the above. [more]
50
Learn more about scoring.

We analyzed this package on Oct 16, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.1
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.2.2 <3.0.0
crypto ^2.1.3 2.1.3
equatable ^0.6.1 0.6.1
flutter 0.0.0
http ^0.12.0+2 0.12.0+2
http_parser ^3.1.3 3.1.3
meta ^1.1.7 1.1.7
mime_type ^0.2.4 0.2.4
Transitive dependencies
async 2.4.0
charcode 1.1.2
collection 1.14.11 1.14.12
convert 2.1.1
path 1.6.4
pedantic 1.8.0+1
sky_engine 0.0.99
source_span 1.5.5
string_scanner 1.0.5
term_glyph 1.1.0
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
dotenv ^1.0.0
flutter_test
mockito ^4.1.1
test ^1.6.3