super_clipboard_syncme 0.9.0-dev.2 super_clipboard_syncme: ^0.9.0-dev.2 copied to clipboard
Comprehensive clipboard access package for Flutter. Supports reading and writing of rich text, images and other formats.
import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:super_clipboard/super_clipboard.dart';
import 'package:flutter_layout_grid/flutter_layout_grid.dart';
import 'widget_for_reader.dart';
void main() async {
runApp(const MyApp());
}
const _notAvailableMessage =
'Clipboard is not available on this platform. Use ClipboardEvents API instead.';
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SuperClipboard Example',
theme: ThemeData(
snackBarTheme: const SnackBarThemeData(
behavior: SnackBarBehavior.floating,
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 16)),
),
primarySwatch: Colors.blue,
useMaterial3: false,
),
home: const MyHomePage(title: 'SuperClipboard Example'),
);
}
}
class Expand extends SingleChildRenderObjectWidget {
const Expand({super.key, required super.child});
@override
RenderObject createRenderObject(BuildContext context) => _RenderExpanded();
}
class _RenderExpanded extends RenderProxyBox {
@override
void layout(Constraints constraints, {bool parentUsesSize = false}) {
final boxConstraints = constraints as BoxConstraints;
super.layout(
boxConstraints.tighten(
width: boxConstraints.maxWidth,
height: boxConstraints.maxHeight,
),
parentUsesSize: parentUsesSize);
}
}
class HomeLayout extends StatelessWidget {
const HomeLayout({
super.key,
required this.mainContent,
required this.buttons,
});
final List<Widget> mainContent;
final List<Widget> buttons;
@override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
if (constraints.maxWidth < 540) {
return ListView(
padding: const EdgeInsets.all(16),
children: [
LayoutGrid(
autoPlacement: AutoPlacement.rowDense,
columnSizes: [1.5.fr, 2.fr],
rowSizes: const [auto, auto, auto, auto],
gridFit: GridFit.expand,
rowGap: 10,
columnGap: 10,
children: buttons.map((e) => Expand(child: e)).toList(),
),
const SizedBox(height: 16),
...mainContent,
],
);
} else {
return Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: buttons
.intersperse(const SizedBox(height: 10))
.toList(growable: false),
),
),
),
),
VerticalDivider(
color: Colors.blueGrey.shade100,
thickness: 1,
width: 1,
),
Expanded(
child: ListView(
padding: const EdgeInsets.all(16),
children: mainContent,
),
)
],
);
}
});
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
void showMessage(String message) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(message),
duration: const Duration(milliseconds: 1500),
),
);
}
@override
void initState() {
super.initState();
ClipboardEvents.instance?.registerPasteEventListener(_onPasteEvent);
}
@override
void dispose() {
super.dispose();
ClipboardEvents.instance?.unregisterPasteEventListener(_onPasteEvent);
}
void copyText() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem();
item.add(Formats.htmlText('<b>This is a <em>HTML</en> value</b>.'));
item.add(Formats.plainText('This is a plaintext value.'));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyTextLazy() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem();
item.add(Formats.htmlText.lazy(() {
showMessage('Lazy rich text requested.');
return '<b>This is a <em>HTML</en> value</b> generated <u>on demand</u>.';
}));
item.add(Formats.plainText.lazy(() {
showMessage('Lazy plain text requested.');
return 'This is a plaintext value generated on demand.';
}));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyImage() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final image = await createImageData(Colors.red);
final item = DataWriterItem(suggestedName: 'RedCircle.png');
item.add(Formats.png(image));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyImageLazy() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem(suggestedName: 'BlueCircle.png');
item.add(Formats.png.lazy(() {
showMessage('Lazy image requested.');
return createImageData(Colors.blue);
}));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyCustomData() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem();
item.add(formatCustom(Uint8List.fromList([1, 2, 3, 4])));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyCustomDataLazy() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem();
item.add(formatCustom.lazy(() async {
showMessage('Lazy custom data requested.');
return Uint8List.fromList([1, 2, 3, 4, 5, 6]);
}));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void copyUri() async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final item = DataWriterItem();
item.add(Formats.uri(NamedUri(
Uri.parse('https://github.com/superlistapp/super_native_extensions'),
name: 'Super Native Extensions')));
await clipboard.write([item]);
} else {
showMessage(_notAvailableMessage);
}
}
void _paste(ClipboardReader reader) async {
final readers = await Future.wait(
reader.items.map((e) => ReaderInfo.fromReader(e)),
);
if (!mounted) {
return;
}
buildWidgetsForReaders(context, readers, (widgets) {
setState(() {
contentWidgets = widgets;
});
});
}
void _onPasteEvent(ClipboardReadEvent event) async {
_paste(await event.getClipboardReader());
}
var contentWidgets = <Widget>[];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: HomeLayout(
mainContent: contentWidgets
.intersperse(const SizedBox(height: 10))
.toList(growable: false),
buttons: [
OutlinedButton(
onPressed: copyText,
child: const Text('Copy Text'),
),
OutlinedButton(
onPressed: copyTextLazy, child: const Text('Copy Text - Lazy')),
OutlinedButton(onPressed: copyImage, child: const Text('Copy Image')),
OutlinedButton(
onPressed: copyImageLazy, child: const Text('Copy Image - Lazy')),
OutlinedButton(
onPressed: copyCustomData, child: const Text('Copy Custom')),
OutlinedButton(
onPressed: copyCustomDataLazy,
child: const Text('Copy Custom - Lazy')),
OutlinedButton(onPressed: copyUri, child: const Text('Copy URI')),
OutlinedButton(
onPressed: () async {
final clipboard = SystemClipboard.instance;
if (clipboard != null) {
final reader = await clipboard.read();
_paste(reader);
} else {
showMessage(_notAvailableMessage);
}
},
style: OutlinedButton.styleFrom(
backgroundColor: Colors.blue.shade600,
foregroundColor: Colors.white,
),
child: const Text('Paste')),
],
),
);
}
}
Future<Uint8List> createImageData(Color color) async {
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
final paint = Paint()..color = color;
canvas.drawOval(const Rect.fromLTWH(0, 0, 200, 200), paint);
final picture = recorder.endRecording();
final image = await picture.toImage(200, 200);
final data = await image.toByteData(format: ui.ImageByteFormat.png);
return data!.buffer.asUint8List();
}