flutter-sdk .A Flutter integration for Transloadit's file uploading and encoding service.
Transloadit is a service that helps you handle file uploads, resize, crop and watermark your images, make GIFs, transcode your videos, extract thumbnails, generate audio waveforms, and so much more. In short, Transloadit is the Swiss Army Knife for your files.
This is a Flutter SDK to make it easy to talk to the Transloadit REST API.
flutter pub add transloadit
Firstly you need to create a Transloadit client, using your authentication credentials. This will allow us to make requests to the Transloadit API.
TransloaditClient client = TransloaditClient(
authKey: 'KEY',
authSecret: 'SECRET');
This example shows how to resize an image using the Transloadit API.
TransloaditClient client = TransloaditClient(
authKey: 'KEY',
authSecret: 'SECRET');
// First we create our assembly
TransloaditAssembly assembly = client.newAssembly();
// Next we add two steps, one to import a file, and another to resize it to 400px tall
assembly.addStep("import", "/http/import",
{"url": "https://demos.transloadit.com/inputs/chameleon.jpg"});
assembly.addStep("resize", "/image/resize", {"height": 400});
// We then send this assembly to Transloadit to be processed
TransloaditResponse response = await assembly.createAssembly();
print(response['ok']) // "ASSEMBLY_COMPLETED"
A file from a user's device can be included with an Assembly using the addFile method.
TransloaditClient client = TransloaditClient(
authKey: 'KEY',
authSecret: 'SECRET');
// First we create our assembly
TransloaditAssembly assembly = client.newAssembly();
// Add a local file to be sent along with the assembly via the Tus protocol
assembly.addFile(file: file!);
assembly.addStep("resize", "/image/resize", {"height": 400});
// We then send this assembly to Transloadit to be processed
TransloaditResponse response = await assembly.createAssembly();
print(response['ok']) // "ASSEMBLY_COMPLETED"
TransloaditClient client = TransloaditClient(
authKey: 'KEY',
authSecret: 'SECRET');
// Create an assembly from a template ID
TransloaditAssembly assembly = client.runTemplate(
templateID: 'TEMPLATE_ID',
params: {'fields': {'input': 'items.jpg'}});
// We then send this assembly to Transloadit to be processed
TransloaditResponse response = await assembly.createAssembly();
print(response.data["ok"]); // "ASSEMBLY_COMPLETED"
These two callback methods track the progress of the Tus upload, not the Transloadit Assembly.
TransloaditResponse response = await assembly.createAssembly(
onProgress: (progressValue) {
print(progressValue); // Float from 0-100
},
onComplete: () {
// Run on completion
}),
);
For a fully working example app, check out examples/.
Full documentation for all classes and methods can be found on pub.dev
Run this command:
With Flutter:
$ flutter pub add transloadit
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):
dependencies:
transloadit: ^0.2.0
Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:transloadit/transloadit.dart';
import 'package:universal_io/io.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:transloadit/transloadit.dart';
void main() {
runApp(MyApp());
}
Map<int, Color> dark = {
50: Color.fromRGBO(17, 30, 50, .1),
100: Color.fromRGBO(17, 30, 50, .2),
200: Color.fromRGBO(17, 30, 50, .3),
300: Color.fromRGBO(17, 30, 50, .4),
400: Color.fromRGBO(17, 30, 50, .5),
500: Color.fromRGBO(17, 30, 50, .6),
600: Color.fromRGBO(17, 30, 50, .7),
700: Color.fromRGBO(17, 30, 50, .8),
800: Color.fromRGBO(17, 30, 50, .9),
900: Color.fromRGBO(17, 30, 50, 1),
};
Map<int, Color> light = {
50: Color.fromRGBO(0, 120, 209, .1),
100: Color.fromRGBO(0, 120, 209, .2),
200: Color.fromRGBO(0, 120, 209, .3),
300: Color.fromRGBO(0, 120, 209, .4),
400: Color.fromRGBO(0, 120, 209, .5),
500: Color.fromRGBO(0, 120, 209, .6),
600: Color.fromRGBO(0, 120, 209, .7),
700: Color.fromRGBO(0, 120, 209, .8),
800: Color.fromRGBO(0, 120, 209, .9),
900: Color.fromRGBO(0, 120, 209, 1),
};
MaterialColor transloaditDark = MaterialColor(0xFF111E32, dark);
MaterialColor transloaditLight = MaterialColor(0xFF0078D1, light);
ColorScheme colorScheme = ColorScheme(
primary: transloaditDark,
primaryVariant: dark[500]!,
secondary: transloaditLight,
secondaryVariant: light[200]!,
surface: Colors.white,
background: Colors.white,
error: Colors.redAccent,
onPrimary: Colors.white,
onSecondary: Colors.white,
onSurface: transloaditDark,
onBackground: transloaditDark,
onError: Colors.white,
brightness: Brightness.light);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Transloadit Demo',
theme: ThemeData(
// Define the default brightness and colors.
brightness: Brightness.light,
colorScheme: colorScheme,
sliderTheme: SliderThemeData(
valueIndicatorColor: colorScheme.primary,
activeTrackColor: colorScheme.primary,
activeTickMarkColor: colorScheme.primary,
thumbColor: colorScheme.primary,
inactiveTrackColor: colorScheme.secondaryVariant,
inactiveTickMarkColor: Colors.transparent,
valueIndicatorShape: PaddleSliderValueIndicatorShape(),
)),
home: MyHomePage(title: 'Transloadit Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File? image;
String? imageURL;
double imageRotation = 0;
bool imageZoom = false;
bool isProcessing = false;
bool uploadComplete = false;
double progress = 0;
// Opens a file picker to select an on device file
Future<void> _pickFile() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'png'],
);
if (result != null) {
File file = File(result.files.single.path!);
setState(() {
image = file;
});
} else {
// User canceled the picker
}
}
// Creates a Transloadit assembly to rotate an image by a user-specified amount
Future<void> _processImage() async {
if (image != null) {
setState(() {
isProcessing = true;
});
TransloaditClient client = TransloaditClient(
authKey: '72a70fba93ce41cba617cfd7c2a44b1a',
authSecret: '3b2845e9330051ed3adc06b4217c42e4f504f8f3');
TransloaditAssembly assembly = client.newAssembly();
assembly.addFile(file: image!);
assembly.addStep("resize", "/image/resize", {
"rotation": imageRotation,
"zoom": imageZoom,
"trim_whitespace": true,
"transparent": "#FFFFFF",
"format": "png"
});
TransloaditResponse response = await assembly.createAssembly(
onProgress: (progressValue) {
print(progressValue);
setState(() {
progress = progressValue;
});
},
onComplete: () => setState(() => uploadComplete = true),
);
setState(() {
imageURL = response.data['results']['resize'][0]['ssl_url'];
isProcessing = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_pickFile();
},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
shape: CircularNotchedRectangle(),
notchMargin: 8.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 60,
),
IconButton(
icon: Icon(
Icons.send,
color: Colors.white,
),
onPressed: () {
setState(() {
_processImage();
progress = 0;
uploadComplete = false;
});
},
),
],
),
color: transloaditDark,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TransloaditImage(
isProcessing: isProcessing,
uploadComplete: uploadComplete,
progress: progress,
imageURL: imageURL,
image: image),
Expanded(
child: Column(
children: [
TransloaditToggle(
text: 'Zoom',
value: imageZoom,
onChanged: (value) {
setState(() {
imageZoom = value;
});
},
),
Divider(),
TransloaditSlider(
text: 'Rotation',
value: imageRotation,
max: 360,
divisions: 12,
onChanged: (value) {
setState(() {
imageRotation = value;
});
}),
Divider(),
],
),
),
],
),
);
}
}
class TransloaditSlider extends StatelessWidget {
const TransloaditSlider({
Key? key,
required this.text,
required this.value,
required this.max,
required this.divisions,
required this.onChanged,
}) : super(key: key);
final String text;
final double value;
final double max;
final int divisions;
final Function(double p1) onChanged;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(30, 8, 15, 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
text,
textScaleFactor: 1.5,
),
Slider(
value: value,
min: 0,
max: max,
label: value.ceil().toString(),
divisions: divisions,
onChanged: onChanged),
],
),
);
}
}
class TransloaditToggle extends StatelessWidget {
const TransloaditToggle({
Key? key,
required this.text,
required this.value,
required this.onChanged,
}) : super(key: key);
final String text;
final bool value;
final Function(bool) onChanged;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(30, 8, 15, 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
text,
textScaleFactor: 1.5,
),
Switch(
value: value,
activeColor: transloaditDark,
activeTrackColor: transloaditLight[200],
inactiveThumbColor: transloaditDark,
inactiveTrackColor: transloaditDark[100],
onChanged: onChanged),
],
),
);
}
}
class TransloaditImage extends StatelessWidget {
const TransloaditImage({
Key? key,
required this.isProcessing,
required this.uploadComplete,
required this.progress,
required this.imageURL,
required this.image,
}) : super(key: key);
final bool isProcessing;
final bool uploadComplete;
final double progress;
final String? imageURL;
final File? image;
@override
Widget build(BuildContext context) {
return Expanded(
child: Stack(
alignment: Alignment.center,
children: [
Container(color: Colors.grey[200]),
isProcessing
? uploadComplete
? CircularProgressIndicator()
: Align(
alignment: Alignment.bottomCenter,
child: LinearProgressIndicator(
color: transloaditDark,
backgroundColor: transloaditLight[200],
value: progress / 100,
),
)
: imageURL != null
? Image.network(imageURL!)
: image != null
? Image.file(image!)
: Image(
image: AssetImage('assets/transloadit.png'),
),
],
),
);
}
}