WeChatTweak-macOS/WeChatTweak/ContextMenu.m
Sunny Young 8b3dcc24a0 Add location type message menu tweaks
Add open in Google Maps and Amap menu item
2024-03-25 10:22:42 +08:00

210 lines
9.1 KiB
Objective-C

//
// ContextMenu.m
// WeChatTweak
//
// Created by Sunny Young on 2022/2/1.
// Copyright © 2022 Sunnyyoung. All rights reserved.
//
#import "WeChatTweak.h"
#import "NSBundle+WeChatTweak.h"
#import <CoreImage/CoreImage.h>
typedef NS_ENUM(NSUInteger, OpenMapMenuType) {
OpenMapMenuTypeGoogleMaps = 0,
OpenMapMenuTypeAmap
};
@implementation NSObject (ContextMenu)
static void __attribute__((constructor)) tweak(void) {
[objc_getClass("MMMessageCellView") jr_swizzleMethod:NSSelectorFromString(@"contextMenu") withMethod:@selector(tweak_contextMenu) error:nil];
}
- (id)tweak_contextMenu {
NSMenu *menu = (NSMenu *)[self tweak_contextMenu];
if ([self isKindOfClass:objc_getClass("MMMessageCellView")]) {
switch (((MMMessageCellView *)self).messageTableItem.message.messageType) {
case MessageDataTypeAppUrl: {
ReaderWrap *wrap = ({
ReaderWrap *wrap = nil;
if ([self isKindOfClass:objc_getClass("MMAppSingleReaderMessageCellView")]) {
MMAppSingleReaderMessageCellView *cell = (MMAppSingleReaderMessageCellView *)self;
wrap = cell.readerData;
} else if ([self isKindOfClass:objc_getClass("MMAppMultipleReaderMessageCellView")]) {
MMAppMultipleReaderMessageCellView *cell = (MMAppMultipleReaderMessageCellView *)self;
wrap = (cell.selectedReaderWrapIndex < cell.readerMessages.count) ? cell.readerMessages[cell.selectedReaderWrapIndex] : nil;
} else {
wrap = nil;
}
wrap;
});
if (wrap) {
[menu addItem:NSMenuItem.separatorItem];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.CopyLink"]
action:@selector(tweakCopyLink:)
keyEquivalent:@"c"];
item.target = wrap;
item;
})];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInBrowser"]
action:@selector(tweakOpenLink:)
keyEquivalent:@"o"];
item.target = wrap;
item;
})];
}
break;
}
case MessageDataTypeImage: {
[menu addItem:NSMenuItem.separatorItem];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.IdentifyQRCode"]
action:@selector(tweakIdentifyQRCode:)
keyEquivalent:@"i"];
item.target = self;
item;
})];
break;
}
case MessageDataTypeSticker: {
[menu addItem:NSMenuItem.separatorItem];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.ExportSticker"]
action:@selector(tweakExportSticker:)
keyEquivalent:@"e"];
item.target = self;
item;
})];
break;
}
case MessageDataTypeLocation: {
[menu addItem:NSMenuItem.separatorItem];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInGoogleMaps"]
action:@selector(tweakOpenMaps:)
keyEquivalent:@""];
item.target = self;
item.tag = OpenMapMenuTypeGoogleMaps;
item;
})];
[menu addItem:({
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.OpenInAmap"]
action:@selector(tweakOpenMaps:)
keyEquivalent:@""];
item.target = self;
item.tag = OpenMapMenuTypeAmap;
item;
})];
break;
}
default: {
break;
}
}
}
return menu;
}
- (void)tweakCopyLink:(NSMenuItem *)sender {
ReaderWrap *wrap = sender.target;
if (!wrap) {
return;
}
if (wrap.m_nsUrl) {
[NSPasteboard.generalPasteboard clearContents];
[NSPasteboard.generalPasteboard setString:wrap.m_nsUrl forType:NSStringPboardType];
}
}
- (void)tweakOpenLink:(NSMenuItem *)sender {
ReaderWrap *wrap = sender.target;
if (!wrap) {
return;
}
if (wrap.m_nsUrl && [NSURL URLWithString:wrap.m_nsUrl]) {
[NSWorkspace.sharedWorkspace openURL:[NSURL URLWithString:wrap.m_nsUrl]];
}
}
- (void)tweakIdentifyQRCode:(NSMenuItem *)sender {
NSImage *image = ((MMImageMessageCellView *)self).displayedImage;
if (image) {
NSData *imageData = [image TIFFRepresentation];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{CIDetectorAccuracy: CIDetectorAccuracyHigh}];
NSArray *results = [detector featuresInImage:[CIImage imageWithData:imageData]];
if (results.count) {
CIQRCodeFeature *result = results.firstObject;
NSString *content = result.messageString;
if (content.length) {
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
[pasteboard clearContents];
[pasteboard setString:content forType:NSStringPboardType];
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:({
NSUserNotification *notification = [[NSUserNotification alloc] init];
notification.informativeText = [NSBundle.tweakBundle localizedStringForKey:@"Tweak.MessageMenuItem.IdentifyQRCodeNotification"];
notification;
})];
}
}
}
}
- (void)tweakExportSticker:(NSMenuItem *)sender {
MMMessageCellView *cell = (MMMessageCellView *)sender.target;
MessageData *messageData = cell.messageTableItem.message;
NSString *localID = [messageData savingImageFileNameWithLocalID];
NSString *md5 = [NSDictionary dictionaryWithXMLString:[messageData.msgContent componentsSeparatedByString:@"\n"].lastObject][@"emoji"][@"_md5"];
if (!localID.length || !md5.length) {
return;
}
NSSavePanel *panel = [NSSavePanel savePanel];
[panel setNameFieldStringValue:localID];
[panel setAllowsOtherFileTypes:YES];
[panel setAllowedFileTypes:@[@"gif"]];
[panel setExtensionHidden:NO];
[panel setCanCreateDirectories:YES];
[panel beginSheetModalForWindow:cell.window completionHandler:^(NSModalResponse result) {
if (result == NSModalResponseOK) {
NSString *path = panel.URL.path;
MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
EmoticonMgr *emoticonMgr = [serviceCenter getService:objc_getClass("EmoticonMgr")];
NSData *stickerData = [emoticonMgr getEmotionDataWithMD5:md5];
[stickerData writeToFile:path atomically:YES];
}
}];
}
- (void)tweakOpenMaps:(NSMenuItem *)sender {
MMMessageCellView *cell = (MMMessageCellView *)sender.target;
NSURL *url = ({
NSURL *url = nil;
NSDictionary *location = [NSDictionary dictionaryWithXMLString:cell.messageTableItem.message.msgContent][@"location"];
id x = location[@"_x"];
id y = location[@"_y"];
if (x && y) {
switch (sender.tag) {
case OpenMapMenuTypeGoogleMaps:
url = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.google.com/maps/search/?api=1&query=%@,%@", x, y]];
break;
case OpenMapMenuTypeAmap:
url = [NSURL URLWithString:[NSString stringWithFormat:@"https://uri.amap.com/marker?position=%@,%@", y, x]];
break;
default:
break;
}
}
url;
});
if (url) {
[NSWorkspace.sharedWorkspace openURL:url];
}
}
@end