Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: support for customize copy and cut Embeddables to Clipboard #2067

Merged

Conversation

CatHood0
Copy link
Collaborator

@CatHood0 CatHood0 commented Jul 25, 2024

Description

Before this PR, we always copy or cut an Embeddable with a empty text, making also more easy to getting back a Embed when the user paste it, but, this could be an issue for users that only want to get the plain text from a Embed. To fix this i add some classes to override this behavior.

CopyCutService and CopyCutServiceProvider

CopyCutService is an interface that let us modify the behavior of getCopyCutAction that let us return some text or an object that will be copied to the Clipboard.

It looks like:

typedef CopyCutAction = Object? Function(dynamic data);

/// An abstraction to make it easy to provide different implementations
/// For copy or cut actions from a Line (just for embeddable blocks)
@immutable
abstract class CopyCutService {
  /// Get the CopyCutAction by the type
  /// of the embeddable (this type is decided by
  /// the property type of that class)
  CopyCutAction? getCopyCutAction(String type);
}

CopyCutServiceProvider it's very similiar to ClipboardServiceProvider. Just provide an instance to be modified and used by any resource of the project.

It looks like:

class CopyCutServiceProvider {
  const CopyCutServiceProvider._();
  static CopyCutService _instance = DefaultCopyCutService();

  static CopyCutService get instance => _instance;

  static void setInstance(CopyCutService service) {
    _instance = service;
  }

  static void setInstanceToDefault() {
    _instance = DefaultCopyCutService();
  }
}

Note

By default CopyCutServiceProvider use DefaultCopyCutService that just return an empty text.

It looks like:

class DefaultCopyCutService extends CopyCutService {
  @override
  CopyCutAction? getCopyCutAction(String type) {
    return (data) => Embed.kObjectReplacementCharacter;
  }
}

Example

If we have a Embeddable like:

class ContentTagEmbed extends Embeddable {
  const ContentTagEmbed(
    String value,
  ) : super(tagType, value);

  static const String tagType = 'content_tag';

  static ContentTagEmbed fromDocument(Document document) => ContentTagEmbed(jsonEncode(document.toDelta().toJson()));

  Document get document => Document.fromJson(jsonDecode(data));
}

To detect this Embed, we just need to create a custom implementation of CopyCutService

class CopyCutServiceTagContent extends CopyCutService {
  
 @override
  CopyCutPlainText? getCopyCutAction(String type) {
    if (type == 'content_tag') {
      return (data) => data.toString();
    } 
    // returning this String maintain the default behavior for others Embed that doesn't need to be plain
    return (data) => '\uFFFC';
  }
}

And after we just need to set this instance to the CopyCutServiceProvider:

CopyCutServiceProvider.setInstance(CopyCutServiceTagContent());
clideo_editor_e7cbeac8d41c4a6d8b55acd082b3cc3f.mp4

Related Issues

@singerdmx
Copy link
Owner

Nice

@singerdmx singerdmx merged commit ac5a823 into singerdmx:master Jul 25, 2024
2 checks passed
@@ -0,0 +1,13 @@
import 'package:flutter/foundation.dart';

typedef CopyCutAction = Object? Function(dynamic data);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use Object? instead of dynamic?

Copy link
Collaborator Author

@CatHood0 CatHood0 Jul 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use dynamic to avoid transforming the data from Embeddable objects. But, i'll change it soon to avoid unexpected behaviors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants