diff --git a/README.md b/README.md index ec0d32d..f3581c9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,10 @@ flutter pub add highlights_plugin ```dart final plugin = HighlightsPlugin(debug: true); +final success = await plugin.initialize(); +``` + +```dart // ['kotlin', 'dart', 'swift', 'php', 'java', ...] final languages = await plugin.getLanguages(); // ['monokai', 'darcula', 'notepad', ...] diff --git a/android/src/main/kotlin/dev/snipme/highlights_plugin/HighlightsPlugin.kt b/android/src/main/kotlin/dev/snipme/highlights_plugin/HighlightsPlugin.kt index 848a7d9..7ee20c9 100644 --- a/android/src/main/kotlin/dev/snipme/highlights_plugin/HighlightsPlugin.kt +++ b/android/src/main/kotlin/dev/snipme/highlights_plugin/HighlightsPlugin.kt @@ -31,40 +31,33 @@ class HighlightsPlugin : FlutterPlugin, MethodCallHandler { } override fun onMethodCall(call: MethodCall, result: Result) { - when (call.method) { - "getHighlights" -> { - updateInstance( - code = call.argument("code"), - language = SyntaxLanguage.getByName(call.argument("language") ?: ""), - theme = SyntaxThemes.getByName(call.argument("theme") ?: "", useDarkMode), - emphasisLocations = tryGetEmphasisFromJson(call.argument("emphasisLocations")) - ) + try { + when (call.method) { + "getHighlights" -> { + updateInstance( + code = call.argument("code"), + language = SyntaxLanguage.getByName(call.argument("language") ?: ""), + theme = SyntaxThemes.getByName(call.argument("theme") ?: "", useDarkMode), + emphasisLocations = tryGetEmphasisFromJson(call.argument("emphasisLocations")) + ) - highlights.getHighlightsAsync( - object: DefaultHighlightsResultListener() { - override fun onSuccess(highlights: List) { - result.success(highlights.toJson()) - } + val output = highlights.getHighlights() + result.success(output.toJson()) + } - override fun onCancel() { - result.success(null) - } + "getLanguages" -> result.success(SyntaxLanguage.getNames()) + "getThemes" -> result.success(SyntaxThemes.getNames(useDarkMode)) + "setDarkMode" -> { + useDarkMode = call.argument("useDarkMode") ?: false + result.success(null) + } - override fun onError(exception: Throwable) { - result.error("Error", exception.message, null) - } - } - ) - } - "getLanguages" -> result.success(SyntaxLanguage.getNames()) - "getThemes" -> result.success(SyntaxThemes.getNames(useDarkMode)) - "setDarkMode" -> { - useDarkMode = call.argument("useDarkMode") ?: false - result.success(null) - } - else -> { - result.notImplemented() + else -> { + result.notImplemented() + } } + } catch (e: Exception) { + result.error("Error", e.message, e) } } diff --git a/example/lib/main.dart b/example/lib/main.dart index 315c029..e23b665 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:highlights_plugin/highlights_plugin.dart'; import 'package:highlights_plugin/model/phrase_location.dart'; @@ -23,7 +25,7 @@ class _MyAppState extends State { final List _emphasis = []; Future _updateDarkMode(bool isDark) async { - _highlightsPlugin.setDarkMode(isDark); + await _highlightsPlugin.setDarkMode(isDark); _updateHighlights(_code ?? ''); } @@ -41,19 +43,14 @@ class _MyAppState extends State { _updateHighlights(_code ?? ''); } - Future _updateHighlights(String code) async { + _updateHighlights(String code) { _code = code; _highlightsPlugin - .getHighlights( - _code ?? '', - _language, - _theme, - _emphasis, - ) - .then((value) { + .getHighlights(_code ?? '', _language, _theme, _emphasis) + .then((highlights) { setState(() { - value.sort((a, b) => a.location.start.compareTo(b.location.start)); - _highlights = value.map((highlight) => highlight.toString()).toList(); + _highlights = + highlights.map((highlight) => highlight.toString()).toList(); }); }); } @@ -63,6 +60,12 @@ class _MyAppState extends State { _updateHighlights(_code ?? ''); } + @override + void initState() { + super.initState(); + unawaited(_highlightsPlugin.initialize()); + } + @override Widget build(BuildContext context) { return MaterialApp( diff --git a/example/macos/Podfile.lock b/example/macos/Podfile.lock index 2d8595f..b553f83 100644 --- a/example/macos/Podfile.lock +++ b/example/macos/Podfile.lock @@ -1,21 +1,15 @@ PODS: - FlutterMacOS (1.0.0) - - highlights_plugin (0.0.1): - - FlutterMacOS DEPENDENCIES: - FlutterMacOS (from `Flutter/ephemeral`) - - highlights_plugin (from `Flutter/ephemeral/.symlinks/plugins/highlights_plugin/macos`) EXTERNAL SOURCES: FlutterMacOS: :path: Flutter/ephemeral - highlights_plugin: - :path: Flutter/ephemeral/.symlinks/plugins/highlights_plugin/macos SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - highlights_plugin: 8a7d54a1fffabf787c85c83f91317b3cc3bdd56c PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/example/macos/Runner.xcodeproj/project.pbxproj b/example/macos/Runner.xcodeproj/project.pbxproj index bcf17bf..9f75b2b 100644 --- a/example/macos/Runner.xcodeproj/project.pbxproj +++ b/example/macos/Runner.xcodeproj/project.pbxproj @@ -184,7 +184,6 @@ 33CC10EB2044A3C60003C045 /* Resources */, 33CC110E2044A8840003C045 /* Bundle Framework */, 3399D490228B24CF009A79C7 /* ShellScript */, - CD40F6F01B76A7B123DDBE56 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -203,7 +202,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -314,23 +313,6 @@ shellPath = /bin/sh; shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; }; - CD40F6F01B76A7B123DDBE56 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ diff --git a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 334149c..9a0d9e7 100644 --- a/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/example/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Bool { return true diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index e993fef..1afa8d0 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -18,8 +18,8 @@ void main() { // Verify that platform version is retrieved. expect( find.byWidgetPredicate( - (Widget widget) => widget is Text && - widget.data!.startsWith('Running on:'), + (Widget widget) => + widget is Text && widget.data!.startsWith('Running on:'), ), findsOneWidget, ); diff --git a/ios/Classes/SwiftHighlightsPlugin.swift b/ios/Classes/SwiftHighlightsPlugin.swift index 52a5dd5..00bcf50 100644 --- a/ios/Classes/SwiftHighlightsPlugin.swift +++ b/ios/Classes/SwiftHighlightsPlugin.swift @@ -45,30 +45,10 @@ public class SwiftHighlightsPlugin: NSObject, FlutterPlugin { theme: theme, emphasisLocations: emphasis ) - - class Listener: DefaultHighlightsResultListener { - var flutterResult: FlutterResult - - init(flutterResult: @escaping FlutterResult) { - self.flutterResult = flutterResult - } - - override func onStart() {} - - override func onCancel() { - flutterResult(nil) - } - - override func onSuccess(result: [CodeHighlight]) { - flutterResult(ExtensionsKt.toJson(result)) - } - override func onError(exception: KotlinThrowable) { - flutterResult(exception) - } - } + let highlightList = highlights.getHighlights(); - highlights.getHighlightsAsync(listener: Listener(flutterResult: result)); + result(ExtensionsKt.toJson(highlightList)) case "setDarkMode": let map = call.arguments as! Dictionary useDarkMode = map["useDarkMode"] as? Bool ?? false diff --git a/lib/highlights_interface.dart b/lib/highlights_interface.dart index 56c6616..4044ec2 100644 --- a/lib/highlights_interface.dart +++ b/lib/highlights_interface.dart @@ -2,6 +2,8 @@ import 'package:highlights_plugin/model/code_highlight.dart'; import 'package:highlights_plugin/model/phrase_location.dart'; abstract interface class HighlightsInterface { + Future initialize(); + Future> getHighlights( String code, String language, diff --git a/lib/highlights_platform_interface.dart b/lib/highlights_platform_interface.dart new file mode 100644 index 0000000..cefb6a8 --- /dev/null +++ b/lib/highlights_platform_interface.dart @@ -0,0 +1,59 @@ +import 'package:highlights_plugin/model/code_highlight.dart'; +import 'package:highlights_plugin/model/phrase_location.dart'; +import 'package:highlights_plugin/native_platform_interface.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + +import 'highlights_interface.dart'; +import 'method_index.dart' as methods; + +abstract class HighlightsPlatformInterface extends PlatformInterface + implements HighlightsInterface { + HighlightsPlatformInterface() : super(token: _token); + + static final Object _token = Object(); + + static bool debug = false; + + static HighlightsPlatformInterface _instance = + NativePlatformInterface(debug: debug); + + static HighlightsPlatformInterface get instance => _instance; + + static set instance(HighlightsPlatformInterface instance) { + PlatformInterface.verifyToken(instance, _token); + _instance = instance; + } + + @override + Future initialize() { + throw UnimplementedError('${methods.initialize} has not been implemented.'); + } + + @override + Future> getHighlights( + String? code, + String? language, + String? theme, + List? emphasisLocations, + ) { + throw UnimplementedError( + '${methods.getHighlights} has not been implemented.'); + } + + @override + Future> getLanguages() { + throw UnimplementedError( + '${methods.getLanguages} has not been implemented.'); + } + + @override + Future> getThemes() { + throw UnimplementedError('${methods.getThemes} has not been implemented.'); + } + + @override + Future setDarkMode(bool useDarkMode) { + throw UnimplementedError( + '${methods.setDarkMode} has not been implemented.'); + } +} diff --git a/lib/highlights_plugin.dart b/lib/highlights_plugin.dart index b56e1f7..04dd464 100644 --- a/lib/highlights_plugin.dart +++ b/lib/highlights_plugin.dart @@ -1,27 +1,32 @@ import 'package:flutter/cupertino.dart'; +import 'package:highlights_plugin/highlights_platform_interface.dart'; import 'package:highlights_plugin/model/code_highlight.dart'; import 'package:highlights_plugin/model/phrase_location.dart'; import 'package:highlights_plugin/method_index.dart' as methods; import 'highlights_interface.dart'; -import 'highlights_plugin_platform_interface.dart'; class HighlightsPlugin implements HighlightsInterface { HighlightsPlugin({this.debug = false}) { + // TODO Test logger flag // Setup before first `instance` getter call - HighlightsPluginPlatform.debug = debug; + HighlightsPlatformInterface.debug = debug; } final bool debug; + @override + Future initialize() => + HighlightsPlatformInterface.instance.initialize(); + @override Future> getHighlights( String code, String? language, String? theme, List? emphasisLocations, - ) async { + ) { try { - return await HighlightsPluginPlatform.instance.getHighlights( + return HighlightsPlatformInterface.instance.getHighlights( code, language, theme, @@ -29,14 +34,14 @@ class HighlightsPlugin implements HighlightsInterface { ); } catch (e, st) { _printDebugInfo(methods.getHighlights, e, st); - return []; + return Future.value([]); } } @override Future> getLanguages() async { try { - return await HighlightsPluginPlatform.instance.getLanguages(); + return await HighlightsPlatformInterface.instance.getLanguages(); } catch (e, st) { _printDebugInfo(methods.getLanguages, e, st); return []; @@ -46,7 +51,7 @@ class HighlightsPlugin implements HighlightsInterface { @override Future> getThemes() async { try { - return await HighlightsPluginPlatform.instance.getThemes(); + return await HighlightsPlatformInterface.instance.getThemes(); } catch (e, st) { _printDebugInfo(methods.getThemes, e, st); return []; @@ -56,7 +61,7 @@ class HighlightsPlugin implements HighlightsInterface { @override Future setDarkMode(bool useDarkMode) { try { - return HighlightsPluginPlatform.instance.setDarkMode(useDarkMode); + return HighlightsPlatformInterface.instance.setDarkMode(useDarkMode); } catch (e, st) { _printDebugInfo(methods.setDarkMode, e, st); return Future.value(); diff --git a/lib/highlights_plugin_platform_interface.dart b/lib/highlights_plugin_platform_interface.dart deleted file mode 100644 index 09f286b..0000000 --- a/lib/highlights_plugin_platform_interface.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:highlights_plugin/model/code_highlight.dart'; -import 'package:highlights_plugin/model/phrase_location.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; - -import 'highlights_interface.dart'; -import 'highlights_plugin_method_channel.dart'; -import 'method_index.dart' as methods; - -abstract class HighlightsPluginPlatform extends PlatformInterface - implements HighlightsInterface { - /// Constructs a HighlightsPluginPlatform. - HighlightsPluginPlatform() : super(token: _token); - - static final Object _token = Object(); - - static bool debug = false; - - static HighlightsPluginPlatform _instance = - MethodChannelHighlightsPlugin(debug: debug); - - /// The default instance of [HighlightsPluginPlatform] to use. - /// - /// Defaults to [MethodChannelHighlightsPlugin]. - static HighlightsPluginPlatform get instance => _instance; - - /// Platform-specific implementations should set this with their own - /// platform-specific class that extends [HighlightsPluginPlatform] when - /// they register themselves. - static set instance(HighlightsPluginPlatform instance) { - PlatformInterface.verifyToken(instance, _token); - _instance = instance; - } - - @override - Future> getHighlights( - String? code, - String? language, - String? theme, - List? emphasisLocations, - ) { - throw UnimplementedError('${methods.getHighlights} has not been implemented.'); - } - - @override - Future> getLanguages() { - throw UnimplementedError('${methods.getLanguages} has not been implemented.'); - } - - @override - Future> getThemes() { - throw UnimplementedError('${methods.getThemes} has not been implemented.'); - } - - @override - Future setDarkMode(bool useDarkMode) { - throw UnimplementedError('${methods.setDarkMode} has not been implemented.'); - } -} diff --git a/lib/method_index.dart b/lib/method_index.dart index 1f18601..c3654dc 100644 --- a/lib/method_index.dart +++ b/lib/method_index.dart @@ -1,4 +1,5 @@ +const initialize = 'initialize'; const getHighlights = 'getHighlights'; const getLanguages = 'getLanguages'; const getThemes = 'getThemes'; -const setDarkMode = 'setDarkMode'; \ No newline at end of file +const setDarkMode = 'setDarkMode'; diff --git a/lib/model/phrase_location.dart b/lib/model/phrase_location.dart index ca4b4a7..bfcb47d 100644 --- a/lib/model/phrase_location.dart +++ b/lib/model/phrase_location.dart @@ -24,9 +24,7 @@ class PhraseLocation { bool operator ==(Object other) { if (identical(this, other)) return true; - return other is PhraseLocation && - other.start == start && - other.end == end; + return other is PhraseLocation && other.start == start && other.end == end; } @override diff --git a/lib/highlights_plugin_method_channel.dart b/lib/native_platform_interface.dart similarity index 74% rename from lib/highlights_plugin_method_channel.dart rename to lib/native_platform_interface.dart index 06af844..834f726 100644 --- a/lib/highlights_plugin_method_channel.dart +++ b/lib/native_platform_interface.dart @@ -1,29 +1,46 @@ import 'dart:convert'; +import 'dart:core'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; import 'package:highlights_plugin/highlights_interface.dart'; +import 'package:highlights_plugin/highlights_platform_interface.dart'; import 'package:highlights_plugin/model/code_highlight.dart'; import 'package:highlights_plugin/model/phrase_location.dart'; import 'package:highlights_plugin/method_index.dart' as methods; -import 'package:collection/collection.dart'; - -import 'highlights_plugin_platform_interface.dart'; -/// An implementation of [HighlightsPluginPlatform] that uses method channels. -class MethodChannelHighlightsPlugin extends HighlightsPluginPlatform +class NativePlatformInterface extends HighlightsPlatformInterface implements HighlightsInterface { - MethodChannelHighlightsPlugin({required this.debug}); + NativePlatformInterface({required this.debug}); - /// The method channel used to interact with the native platform. @visibleForTesting - final methodChannel = const MethodChannel('highlights_plugin'); + late MethodChannel methodChannel; final bool debug; List? _cachedLanguages; List? _cachedThemes; + @override + Future initialize() async { + try { + BackgroundIsolateBinaryMessenger.ensureInitialized( + ServicesBinding.rootIsolateToken!, + ); + methodChannel = MethodChannel( + 'highlights_plugin', + StandardMethodCodec(), + BackgroundIsolateBinaryMessenger.instance, + ); + _debugPrint('${methods.initialize}: Initialization completed!'); + return true; + } catch (e, s) { + _debugPrint('${methods.initialize}: Error: $e, $s'); + return false; + } + } + @override Future> getHighlights( String? code, @@ -33,17 +50,20 @@ class MethodChannelHighlightsPlugin extends HighlightsPluginPlatform ) async { final arguments = { "code": code, - "language": (await _getLanguage(language)), - "theme": (await _getTheme(theme)), + "language": await _getLanguage(language), + "theme": await _getTheme(theme), "emphasisLocations": jsonEncode(emphasisLocations), }; - final json = await methodChannel.invokeMethod( + final highlightsJson = await methodChannel.invokeMethod( methods.getHighlights, arguments, ); - final data = jsonDecode(json); + final data = await compute( + (json) => jsonDecode(json), + highlightsJson, + ); if (data is List) { return data.map((e) => CodeHighlight.fromJson(e)).toList(); diff --git a/test/highlights_plugin_method_channel_test.dart b/test/native_platform_interface_test.dart similarity index 91% rename from test/highlights_plugin_method_channel_test.dart rename to test/native_platform_interface_test.dart index f7978b4..d90e678 100644 --- a/test/highlights_plugin_method_channel_test.dart +++ b/test/native_platform_interface_test.dart @@ -1,14 +1,13 @@ import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:highlights_plugin/highlights_plugin_method_channel.dart'; import 'package:highlights_plugin/method_index.dart' as methods; import 'package:highlights_plugin/model/code_highlight.dart'; import 'package:highlights_plugin/model/phrase_location.dart'; +import 'package:highlights_plugin/native_platform_interface.dart'; void main() { - MethodChannelHighlightsPlugin platform = - MethodChannelHighlightsPlugin(debug: true); + NativePlatformInterface platform = NativePlatformInterface(debug: true); const MethodChannel channel = MethodChannel('highlights_plugin'); TestWidgetsFlutterBinding.ensureInitialized();