Add tweak settings preference panel

This commit is contained in:
Sunnyyoung
2017-08-12 20:29:08 +08:00
parent e4fc52d197
commit 1a6294e9d0
27 changed files with 515 additions and 73 deletions
+15
View File
@@ -0,0 +1,15 @@
//
// NSBundle+WeChatTweak.h
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface NSBundle (WeChatTweak)
+ (instancetype)tweakBundle;
@end
+17
View File
@@ -0,0 +1,17 @@
//
// NSBundle+WeChatTweak.m
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import "NSBundle+WeChatTweak.h"
@implementation NSBundle (WeChatTweak)
+ (instancetype)tweakBundle {
return [NSBundle bundleWithIdentifier:@"net.sunnyyoung.WeChatTweak"];
}
@end
+15
View File
@@ -0,0 +1,15 @@
//
// NSString+WeChatTweak.h
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (WeChatTweak)
- (NSString *)tweak_subStringFrom:(NSString *)beginString to:(NSString *)endString;
@end
+20
View File
@@ -0,0 +1,20 @@
//
// NSString+WeChatTweak.m
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import "NSString+WeChatTweak.h"
@implementation NSString (WeChatTweak)
- (NSString *)tweak_subStringFrom:(NSString *)beginString to:(NSString *)endString {
NSRange begin = [self rangeOfString:beginString];
NSRange end = [self rangeOfString:endString];
NSRange range = NSMakeRange(begin.location + begin.length, end.location - begin.location - begin.length);
return [self substringWithRange:range];
}
@end
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
//
// TweakPreferecesController.h
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import "WeChatTweakHeaders.h"
typedef NS_ENUM(NSUInteger, RevokeNotificationType) {
RevokeNotificationTypeFollow = 0,
RevokeNotificationTypeReceiveAll,
RevokeNotificationTypeDisable,
};
static NSString * const WeChatTweakPreferenceAutoAuthKey = @"WeChatTweakPreferenceAutoAuthKey";
static NSString * const WeChatTweakPreferenceRevokeNotificationTypeKey = @"WeChatTweakPreferenceRevokeNotificationTypeKey";
@interface TweakPreferecesController : NSViewController
@end
+73
View File
@@ -0,0 +1,73 @@
//
// TweakPreferecesController.m
// WeChatTweak
//
// Created by Sunnyyoung on 2017/8/12.
// Copyright © 2017年 Sunnyyoung. All rights reserved.
//
#import "TweakPreferecesController.h"
#import "NSBundle+WeChatTweak.h"
@interface TweakPreferecesController () <MASPreferencesViewController>
@property (weak) IBOutlet NSPopUpButton *autoAuthButton;
@property (weak) IBOutlet NSPopUpButton *notificationTypeButton;
@end
@implementation TweakPreferecesController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)viewWillAppear {
[super viewWillAppear];
[self reloadData];
}
- (void)reloadData {
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
BOOL enabledAutoAuth = [userDefaults boolForKey:WeChatTweakPreferenceAutoAuthKey];
RevokeNotificationType notificationType = [userDefaults integerForKey:WeChatTweakPreferenceRevokeNotificationTypeKey];
[self.autoAuthButton selectItemAtIndex:enabledAutoAuth ? 1 : 0];
[self.notificationTypeButton selectItemAtIndex:notificationType];
}
#pragma mark - Event method
- (IBAction)switchAutoAuthAction:(NSPopUpButton *)sender {
BOOL enabled = sender.indexOfSelectedItem == 1;
[[NSUserDefaults standardUserDefaults] setBool:enabled forKey:WeChatTweakPreferenceAutoAuthKey];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (IBAction)switchNotificationTypeAction:(NSPopUpButton *)sender {
RevokeNotificationType type = sender.indexOfSelectedItem;
[[NSUserDefaults standardUserDefaults] setInteger:type forKey:WeChatTweakPreferenceRevokeNotificationTypeKey];
}
#pragma mark - MASPreferencesViewController
- (NSString *)identifier {
return @"tweak";
}
- (NSString *)toolbarItemLabel {
return @"Tweak";
}
- (NSImage *)toolbarItemImage {
return [[NSBundle tweakBundle] imageForResource:@"Prefs-Tweak"];
}
- (BOOL)hasResizableWidth {
return NO;
}
- (BOOL)hasResizableHeight {
return NO;
}
@end
+95
View File
@@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12121"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="TweakPreferecesController">
<connections>
<outlet property="autoAuthButton" destination="5by-EJ-3f2" id="VIV-sZ-ybx"/>
<outlet property="notificationTypeButton" destination="6x2-KV-p8w" id="Kfn-2a-Yup"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="430" height="92"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="RFE-oR-GRm">
<rect key="frame" x="58" y="55" width="111" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="免手机认证登陆:" id="UiV-zj-l6I">
<font key="font" size="13" name=".PingFangSC-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="B87-eD-uhI">
<rect key="frame" x="72" y="22" width="97" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="消息撤回通知:" id="UKv-CM-nGt">
<font key="font" size="13" name=".PingFangSC-Regular"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5by-EJ-3f2">
<rect key="frame" x="173" y="50" width="64" height="26"/>
<popUpButtonCell key="cell" type="push" title="关闭" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="Vcv-eD-OM9" id="8qB-Jj-tlv">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="sFO-8T-61S">
<items>
<menuItem title="关闭" state="on" id="Vcv-eD-OM9">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="开启" id="KQg-jN-y9a">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="switchAutoAuthAction:" target="-2" id="P6Q-aT-ADE"/>
</connections>
</popUpButton>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="6x2-KV-p8w">
<rect key="frame" x="173" y="17" width="144" height="26"/>
<popUpButtonCell key="cell" type="push" title="跟随消息通知设置" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="gec-CY-E1x" id="wek-GT-N5V">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/>
<menu key="menu" id="H2J-gJ-aGD">
<items>
<menuItem title="跟随消息通知设置" id="gec-CY-E1x">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="全部接收" id="da4-aJ-lEy">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem title="全部关闭" state="on" id="Uk9-Oc-Jtv">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
</items>
</menu>
</popUpButtonCell>
<connections>
<action selector="switchNotificationTypeAction:" target="-2" id="xjO-Ck-wem"/>
</connections>
</popUpButton>
</subviews>
<constraints>
<constraint firstItem="B87-eD-uhI" firstAttribute="trailing" secondItem="RFE-oR-GRm" secondAttribute="trailing" id="3p1-WF-TYr"/>
<constraint firstItem="RFE-oR-GRm" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" id="CWK-cO-DBz"/>
<constraint firstItem="5by-EJ-3f2" firstAttribute="centerY" secondItem="RFE-oR-GRm" secondAttribute="centerY" id="QLN-KI-HUD"/>
<constraint firstItem="RFE-oR-GRm" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="60" id="R8y-0p-4Sk"/>
<constraint firstItem="6x2-KV-p8w" firstAttribute="leading" secondItem="5by-EJ-3f2" secondAttribute="leading" id="WSG-53-r8r"/>
<constraint firstItem="6x2-KV-p8w" firstAttribute="centerY" secondItem="B87-eD-uhI" secondAttribute="centerY" id="gqp-om-e0O"/>
<constraint firstItem="B87-eD-uhI" firstAttribute="top" secondItem="RFE-oR-GRm" secondAttribute="bottom" constant="16" id="lG1-vw-epo"/>
<constraint firstItem="5by-EJ-3f2" firstAttribute="leading" secondItem="RFE-oR-GRm" secondAttribute="trailing" constant="8" id="v9V-TW-Voc"/>
</constraints>
<point key="canvasLocation" x="139" y="164"/>
</customView>
</objects>
</document>
+49 -38
View File
@@ -8,31 +8,9 @@
#import "WeChatTweak.h"
#import "WeChatTweakHeaders.h"
@implementation NSString (WeChatTweak)
- (NSString *)tweak_sessionFromMessage {
NSRange begin = [self rangeOfString:@"<session>"];
NSRange end = [self rangeOfString:@"</session>"];
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
return [self substringWithRange:range];
}
- (NSUInteger)tweak_newMessageIDFromMessage {
NSRange begin = [self rangeOfString:@"<newmsgid>"];
NSRange end = [self rangeOfString:@"</newmsgid>"];
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
return [[self substringWithRange:range] longLongValue];
}
- (NSString *)tweak_replaceMessageFromMessage {
NSRange begin = [self rangeOfString:@"<replacemsg><![CDATA["];
NSRange end = [self rangeOfString:@"]]></replacemsg>"];
NSRange range = NSMakeRange(begin.location + begin.length,end.location - begin.location - begin.length);
return [self substringWithRange:range];
}
@end
#import "NSBundle+WeChatTweak.h"
#import "NSString+WeChatTweak.h"
#import "TweakPreferecesController.h"
@implementation NSObject (WeChatTweak)
@@ -44,15 +22,17 @@ static void __attribute__((constructor)) tweak(void) {
[objc_getClass("AppDelegate") jr_swizzleMethod:NSSelectorFromString(@"applicationShouldTerminate:") withMethod:@selector(tweak_applicationShouldTerminate:) error:nil];
[objc_getClass("MessageService") jr_swizzleMethod:NSSelectorFromString(@"onRevokeMsg:") withMethod:@selector(tweak_onRevokeMsg:) error:nil];
[objc_getClass("CUtility") jr_swizzleClassMethod:NSSelectorFromString(@"HasWechatInstance") withClassMethod:@selector(tweak_HasWechatInstance) error:nil];
[objc_getClass("MASPreferencesWindowController") jr_swizzleMethod:NSSelectorFromString(@"initWithViewControllers:") withMethod:@selector(tweak_initWithViewControllers:) error:nil];
[objc_getClass("MASPreferencesWindowController") jr_swizzleMethod:NSSelectorFromString(@"viewControllerForIdentifier:") withMethod:@selector(tweak_viewControllerForIdentifier:) error:nil];
}
#pragma mark - No Revoke Message
- (void)tweak_onRevokeMsg:(NSString *)message {
// Decode message
NSString *session = [message tweak_sessionFromMessage];
NSUInteger newMessageID = [message tweak_newMessageIDFromMessage];
NSString *replaceMessage = [message tweak_replaceMessageFromMessage];
NSString *session = [message tweak_subStringFrom:@"<session>" to:@"</session>"];
NSUInteger newMessageID = [message tweak_subStringFrom:@"<newmsgid>" to:@"</newmsgid>"].longLongValue;
NSString *replaceMessage = [message tweak_subStringFrom:@"<replacemsg><![CDATA[" to:@"]]></replacemsg>"];
// Prepare message data
MessageData *localMessageData = [((MessageService *)self) GetMsgData:session svrId:newMessageID];
@@ -74,12 +54,18 @@ static void __attribute__((constructor)) tweak(void) {
});
// Prepare notification information
MMServiceCenter *serviceCenter = [objc_getClass("MMServiceCenter") defaultCenter];
NSUserNotification *userNotification = [[NSUserNotification alloc] init];
BOOL isChatStatusNotifyOpen = YES;
if ([session rangeOfString:@"@chatroom"].location == NSNotFound) {
ContactStorage *contactStorage = [serviceCenter getService:objc_getClass("ContactStorage")];
WCContactData *contact = [contactStorage GetContact:session];
isChatStatusNotifyOpen = [contact isChatStatusNotifyOpen];
userNotification.informativeText = replaceMessage;
} else {
GroupStorage *groupStorage = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("GroupStorage")];
WCContactData *groupContact = [groupStorage GetGroupContact: session];
GroupStorage *groupStorage = [serviceCenter getService:objc_getClass("GroupStorage")];
WCContactData *groupContact = [groupStorage GetGroupContact:session];
isChatStatusNotifyOpen = [groupContact isChatStatusNotifyOpen];
NSString *groupName = groupContact.m_nsNickName.length ? groupContact.m_nsNickName : @"群组";
userNotification.informativeText = [NSString stringWithFormat:@"%@: %@", groupName, replaceMessage];
}
@@ -89,11 +75,17 @@ static void __attribute__((constructor)) tweak(void) {
// Delete message if it is revoke from myself
if ([localMessageData isSendFromSelf]) {
[((MessageService *)self) DelMsg:session msgList:@[localMessageData] isDelAll:NO isManual:YES];
[((MessageService *)self) AddRevokePromptMsg:session msgData: promptMessageData];
[((MessageService *)self) AddRevokePromptMsg:session msgData:promptMessageData];
} else {
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
[((MessageService *)self) AddRevokePromptMsg:session msgData: promptMessageData];
[((MessageService *)self) notifyAddMsgOnMainThread:session msgData: promptMessageData];
[((MessageService *)self) AddRevokePromptMsg:session msgData:promptMessageData];
[((MessageService *)self) notifyAddMsgOnMainThread:session msgData:promptMessageData];
}
// Deliver notification
if (![localMessageData isSendFromSelf]) {
RevokeNotificationType notificationType = [[NSUserDefaults standardUserDefaults] integerForKey:WeChatTweakPreferenceRevokeNotificationTypeKey];
if (notificationType == RevokeNotificationTypeReceiveAll || (notificationType == RevokeNotificationTypeFollow && isChatStatusNotifyOpen)) {
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:userNotification];
}
}
});
}
@@ -119,24 +111,43 @@ static void __attribute__((constructor)) tweak(void) {
[task launch];
}
#pragma mark - Auto auth
#pragma mark - Auto Auth
- (void)tweak_applicationDidFinishLaunching:(NSNotification *)notification {
[self tweak_applicationDidFinishLaunching:notification];
NSString *bundleIdentifier = [[objc_getClass("NSBundle") mainBundle] bundleIdentifier];
NSArray *instances = [objc_getClass("NSRunningApplication") runningApplicationsWithBundleIdentifier:bundleIdentifier];
// Detect multiple instance conflict
if (instances.count == 1) {
BOOL hasInstance = instances.count == 1;
BOOL enabledAutoAuth = [[NSUserDefaults standardUserDefaults] boolForKey:WeChatTweakPreferenceAutoAuthKey];
if (hasInstance && enabledAutoAuth) {
AccountService *accountService = [[objc_getClass("MMServiceCenter") defaultCenter] getService:objc_getClass("AccountService")];
if ([accountService canAutoAuth]) {
[accountService AutoAuth];
}
}
}
- (NSApplicationTerminateReply)tweak_applicationShouldTerminate:(NSApplication *)sender {
return NSTerminateNow;
BOOL enabledAutoAuth = [[NSUserDefaults standardUserDefaults] boolForKey:WeChatTweakPreferenceAutoAuthKey];
if (enabledAutoAuth) {
return NSTerminateNow;
} else {
return [self tweak_applicationShouldTerminate:sender];
}
}
#pragma mark - Preferences Window
- (id)tweak_initWithViewControllers:(NSArray *)arg1 {
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:arg1];
TweakPreferecesController *controller = [[objc_getClass("TweakPreferecesController") alloc] initWithNibName:nil bundle:[NSBundle tweakBundle]];
[viewControllers addObject:controller];
return [self tweak_initWithViewControllers:viewControllers];
}
- (id)tweak_viewControllerForIdentifier:(NSString *)arg1 {
return [self tweak_viewControllerForIdentifier:arg1];
}
@end
+31
View File
@@ -27,6 +27,14 @@
@property(retain, nonatomic) NSString *m_nsNickName;
- (BOOL)isChatStatusNotifyOpen;
@end
@interface ContactStorage : NSObject
- (id)GetContact:(id)arg1;
@end
@interface GroupStorage: NSObject
@@ -57,3 +65,26 @@
- (void)AutoAuth;
@end
@protocol MASPreferencesViewController <NSObject>
@property(readonly, nonatomic) NSString *toolbarItemLabel;
@property(readonly, nonatomic) NSImage *toolbarItemImage;
@property(readonly, nonatomic) NSString *identifier;
@optional
@property(readonly, nonatomic) BOOL hasResizableHeight;
@property(readonly, nonatomic) BOOL hasResizableWidth;
- (NSView *)initialKeyView;
- (void)viewDidDisappear;
- (void)viewWillAppear;
@end
@interface MASPreferencesWindowController : NSWindowController
@property(readonly, nonatomic) NSMutableArray *viewControllers;
- (id)initWithViewControllers:(NSArray *)arg1;
@end