<commit_before>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "FLEColorPanelPlugin.h"

#import <AppKit/AppKit.h>

#include "plugins/color_panel/common/channel_constants.h"

@implementation FLEColorPanelPlugin {
  // The channel used to communicate with Flutter.
  FLEMethodChannel *_channel;
}

+ (void)registerWithRegistrar:(id<FLEPluginRegistrar>)registrar {
  FLEMethodChannel* channel = [FLEMethodChannel
                                   methodChannelWithName:@(plugins_color_panel::kChannelName)
                                   binaryMessenger:registrar.messenger
                               codec:[FLEJSONMethodCodec sharedInstance]];
  FLEColorPanelPlugin* instance = [[FLEColorPanelPlugin alloc] initWithChannel:channel];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (instancetype)initWithChannel:(FLEMethodChannel*)channel {
  self = [super init];
  if (self) {
    _channel = channel;
  }
  return self;
}

/**
 * Handles platform messages generated by the Flutter framework on the color
 * panel channel.
 */
- (void)handleMethodCall:(FLEMethodCall *)call result:(FLEMethodResult)result {
  BOOL handled = YES;
  if ([call.methodName isEqualToString:@(plugins_color_panel::kShowColorPanelMethod)]) {
    if ([call.arguments isKindOfClass:[NSDictionary class]]) {
      BOOL showAlpha =
          [[call.arguments valueForKey:@(plugins_color_panel::kColorPanelShowAlpha)] boolValue];
      [self showColorPanelWithAlpha:showAlpha];
    } else {
      NSLog(@"Malformed call for %@. Expected an NSDictionary but got %@",
            @(plugins_color_panel::kShowColorPanelMethod),
            NSStringFromClass([call.arguments class]));
      handled = NO;
    }
  } else if ([call.methodName isEqualToString:@(plugins_color_panel::kHideColorPanelMethod)]) {
    [self hideColorPanel];
  } else {
    handled = NO;
  }
  // Send an immediate empty success message for handled messages, since the actual color data
  // will be provided in follow-up messages.
  result(handled ? nil : FLEMethodNotImplemented);
}

/**
 * Configures the shared instance of NSColorPanel and makes it the frontmost & key window.
 */
- (void)showColorPanelWithAlpha:(BOOL)showAlpha {
  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  sharedColor.delegate = self;
  [sharedColor setShowsAlpha:showAlpha];
  [sharedColor setTarget:self];
  [sharedColor setAction:@selector(selectedColorDidChange)];
  if (!sharedColor.isKeyWindow) {
    [sharedColor makeKeyAndOrderFront:nil];
  }
}

/**
 * Closes the shared color panel.
 */
- (void)hideColorPanel {
  if (![NSColorPanel sharedColorPanelExists]) {
    return;
  }

  // Disconnect before closing to prevent invoking the close callback.
  [self removeColorPanelConnections];

  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  [sharedColor close];
}

/**
 * Removes the connections from the shared color panel back to this instance.
 */
- (void)removeColorPanelConnections {
  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  [sharedColor setTarget:nil];
  [sharedColor setAction:nil];
  sharedColor.delegate = nil;
}

/**
 * Called when the user selects a color in the color panel. Grabs the selected color from the
 * panel and sends it to Flutter via the '_channel'.
 */
- (void)selectedColorDidChange {
  NSColor *color = [NSColorPanel sharedColorPanel].color;
  NSDictionary *colorDictionary = [self dictionaryWithColor:color];
  [_channel invokeMethod:@(plugins_color_panel::kColorSelectedCallbackMethod)
                  arguments:colorDictionary];
}

/**
 * Converts an instance of NSColor to a dictionary representation suitable for JSON messages.
 *
 * @param color An instance of NSColor.
 * @return An instance of NSDictionary representing the color.
 */
- (NSDictionary *)dictionaryWithColor:(NSColor *)color {
  NSMutableDictionary *result = [NSMutableDictionary dictionary];
  // TODO: Consider being able to pass other type of color space (Gray scale, CMYK, etc).
  NSColor *rgbColor = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
  result[@(plugins_color_panel::kColorComponentAlphaKey)] = @(rgbColor.alphaComponent);
  result[@(plugins_color_panel::kColorComponentRedKey)] = @(rgbColor.redComponent);
  result[@(plugins_color_panel::kColorComponentGreenKey)] = @(rgbColor.greenComponent);
  result[@(plugins_color_panel::kColorComponentBlueKey)] = @(rgbColor.blueComponent);
  return result;
}

#pragma mark - NSWindowDelegate

- (void)windowWillClose:(NSNotification *)notification {
  [self removeColorPanelConnections];
  [_channel invokeMethod:@(plugins_color_panel::kClosedCallbackMethod)
                  arguments:nil];
}<commit_msg>[macOS] Use FLEMethodError on color panel plugin bad arguments (#252)<commit_after>// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "FLEColorPanelPlugin.h"

#import <AppKit/AppKit.h>

#include "plugins/color_panel/common/channel_constants.h"

@implementation FLEColorPanelPlugin {
  // The channel used to communicate with Flutter.
  FLEMethodChannel *_channel;
}

+ (void)registerWithRegistrar:(id<FLEPluginRegistrar>)registrar {
  FLEMethodChannel *channel =
      [FLEMethodChannel methodChannelWithName:@(plugins_color_panel::kChannelName)
                              binaryMessenger:registrar.messenger
                                        codec:[FLEJSONMethodCodec sharedInstance]];
  FLEColorPanelPlugin *instance = [[FLEColorPanelPlugin alloc] initWithChannel:channel];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (instancetype)initWithChannel:(FLEMethodChannel *)channel {
  self = [super init];
  if (self) {
    _channel = channel;
  }
  return self;
}

/**
 * Handles platform messages generated by the Flutter framework on the color
 * panel channel.
 */
- (void)handleMethodCall:(FLEMethodCall *)call result:(FLEMethodResult)result {
  id methodResult = nil;
  if ([call.methodName isEqualToString:@(plugins_color_panel::kShowColorPanelMethod)]) {
    if ([call.arguments isKindOfClass:[NSDictionary class]]) {
      BOOL showAlpha =
          [[call.arguments valueForKey:@(plugins_color_panel::kColorPanelShowAlpha)] boolValue];
      [self showColorPanelWithAlpha:showAlpha];
    } else {
      NSString *errorString =
          [NSString stringWithFormat:@"Malformed call for %@. Expected an NSDictionary but got %@",
                                     @(plugins_color_panel::kShowColorPanelMethod),
                                     NSStringFromClass([call.arguments class])];
      methodResult = [[FLEMethodError alloc] initWithCode:@"Bad arguments"
                                                  message:errorString
                                                  details:nil];
    }
  } else if ([call.methodName isEqualToString:@(plugins_color_panel::kHideColorPanelMethod)]) {
    [self hideColorPanel];
  } else {
    methodResult = FLEMethodNotImplemented;
  }
  // If no errors are generated, send an immediate empty success message for handled messages, since
  // the actual color data will be provided in follow-up messages.
  result(methodResult);
}

/**
 * Configures the shared instance of NSColorPanel and makes it the frontmost & key window.
 */
- (void)showColorPanelWithAlpha:(BOOL)showAlpha {
  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  sharedColor.delegate = self;
  [sharedColor setShowsAlpha:showAlpha];
  [sharedColor setTarget:self];
  [sharedColor setAction:@selector(selectedColorDidChange)];
  if (!sharedColor.isKeyWindow) {
    [sharedColor makeKeyAndOrderFront:nil];
  }
}

/**
 * Closes the shared color panel.
 */
- (void)hideColorPanel {
  if (![NSColorPanel sharedColorPanelExists]) {
    return;
  }

  // Disconnect before closing to prevent invoking the close callback.
  [self removeColorPanelConnections];

  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  [sharedColor close];
}

/**
 * Removes the connections from the shared color panel back to this instance.
 */
- (void)removeColorPanelConnections {
  NSColorPanel *sharedColor = [NSColorPanel sharedColorPanel];
  [sharedColor setTarget:nil];
  [sharedColor setAction:nil];
  sharedColor.delegate = nil;
}

/**
 * Called when the user selects a color in the color panel. Grabs the selected color from the
 * panel and sends it to Flutter via the '_channel'.
 */
- (void)selectedColorDidChange {
  NSColor *color = [NSColorPanel sharedColorPanel].color;
  NSDictionary *colorDictionary = [self dictionaryWithColor:color];
  [_channel invokeMethod:@(plugins_color_panel::kColorSelectedCallbackMethod)
               arguments:colorDictionary];
}

/**
 * Converts an instance of NSColor to a dictionary representation suitable for JSON messages.
 *
 * @param color An instance of NSColor.
 * @return An instance of NSDictionary representing the color.
 */
- (NSDictionary *)dictionaryWithColor:(NSColor *)color {
  NSMutableDictionary *result = [NSMutableDictionary dictionary];
  // TODO: Consider being able to pass other type of color space (Gray scale, CMYK, etc).
  NSColor *rgbColor = [color colorUsingColorSpace:[NSColorSpace genericRGBColorSpace]];
  result[@(plugins_color_panel::kColorComponentAlphaKey)] = @(rgbColor.alphaComponent);
  result[@(plugins_color_panel::kColorComponentRedKey)] = @(rgbColor.redComponent);
  result[@(plugins_color_panel::kColorComponentGreenKey)] = @(rgbColor.greenComponent);
  result[@(plugins_color_panel::kColorComponentBlueKey)] = @(rgbColor.blueComponent);
  return result;
}

#pragma mark - NSWindowDelegate

- (void)windowWillClose:(NSNotification *)notification {
  [self removeColorPanelConnections];
  [_channel invokeMethod:@(plugins_color_panel::kClosedCallbackMethod) arguments:nil];
}
{'fraction_non_alphanumeric': 0.09925076311164555, 'fraction_numerical': 0.0017574692442882249, 'mean_word_length': 4.2005772005772, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 9, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6432410', 'n_tokens_mistral': 3031, 'n_tokens_neox': 2930, 'n_words': 815}