import 'dart:async' show Completer; import 'dart:convert' show utf8; import 'package:flutter/foundation.dart'; // ignore: implementation_imports import 'package:flutter_quill/src/editor_toolbar_controller_shared/clipboard/clipboard_service.dart'; import 'package:super_clipboard/super_clipboard.dart'; /// Implementation based on https://pub.dev/packages/super_clipboard class SuperClipboardService implements ClipboardService { /// Null if the Clipboard API is not supported on this platform /// https://pub.dev/packages/super_clipboard#usage SystemClipboard? _getSuperClipboard() { return SystemClipboard.instance; } SystemClipboard _getSuperClipboardOrThrow() { final clipboard = _getSuperClipboard(); if (clipboard == null) { // To avoid getting this exception, use _canProvide() throw UnsupportedError( 'Clipboard API is not supported on this platform.', ); } return clipboard; } Future _canProvide({required DataFormat format}) async { final clipboard = _getSuperClipboard(); if (clipboard == null) { return false; } final reader = await clipboard.read(); return reader.canProvide(format); } Future _provideFileAsBytes({ required SimpleFileFormat format, }) async { final clipboard = _getSuperClipboardOrThrow(); final reader = await clipboard.read(); final completer = Completer(); reader.getFile( format, (file) async { final bytes = await file.readAll(); completer.complete(bytes); }, onError: completer.completeError, ); final bytes = await completer.future; return bytes; } Future _provideFileAsString({ required SimpleFileFormat format, }) async { final fileBytes = await _provideFileAsBytes(format: format); final fileText = utf8.decode(fileBytes); return fileText; } /// According to super_clipboard docs, will return `null` if the value /// is not available or the data is virtual (macOS and Windows) Future _provideSimpleValueFormatAsString({ required SimpleValueFormat format, }) async { final clipboard = _getSuperClipboardOrThrow(); final reader = await clipboard.read(); final value = await reader.readValue(format); return value; } @override Future canProvideHtmlText() { return _canProvide(format: Formats.htmlText); } @override Future getHtmlText() { return _provideSimpleValueFormatAsString(format: Formats.htmlText); } @override Future canProvideHtmlTextFromFile() { return _canProvide(format: Formats.htmlFile); } @override Future getHtmlTextFromFile() { return _provideFileAsString(format: Formats.htmlFile); } @override Future canProvideMarkdownText() async { // Formats.markdownText or Formats.mdText does not exist yet in super_clipboard return false; } @override Future getMarkdownText() async { // Formats.markdownText or Formats.mdText does not exist yet in super_clipboard throw UnsupportedError( 'SuperClipboardService does not support retrieving image files.', ); } @override Future canProvideMarkdownTextFromFile() async { // Formats.md is for markdown files return _canProvide(format: Formats.md); } @override Future getMarkdownTextFromFile() async { // Formats.md is for markdown files return _provideFileAsString(format: Formats.md); } @override Future canProvidePlainText() { return _canProvide(format: Formats.plainText); } @override Future getPlainText() { return _provideSimpleValueFormatAsString(format: Formats.plainText); } /// This will need to be updated if [getImageFileAsBytes] updated. /// Notice that even if the copied image is JPEG, it still can be provided /// as PNG, will handle JPEG check in case this info is incorrect. @override Future canProvideImageFile() async { final canProvidePngFile = await _canProvide(format: Formats.png); if (canProvidePngFile) { return true; } final canProvideJpegFile = await _canProvide(format: Formats.jpeg); if (canProvideJpegFile) { return true; } return false; } /// This will need to be updated if [canProvideImageFile] updated. @override Future getImageFileAsBytes() async { final canProvidePngFile = await _canProvide(format: Formats.png); if (canProvidePngFile) { return _provideFileAsBytes(format: Formats.png); } return _provideFileAsBytes(format: Formats.jpeg); } @override Future canProvideGifFile() { return _canProvide(format: Formats.gif); } @override Future getGifFileAsBytes() { return _provideFileAsBytes(format: Formats.gif); } @override Future canPaste() async { final clipboard = _getSuperClipboard(); if (clipboard == null) { return false; } final reader = await clipboard.read(); final availablePlatformFormats = reader.platformFormats; return availablePlatformFormats.isNotEmpty; } }