diff --git a/global/HBTSConversationPreferences.x b/global/HBTSConversationPreferences.x index d568bcc..7e17230 100644 --- a/global/HBTSConversationPreferences.x +++ b/global/HBTSConversationPreferences.x @@ -4,6 +4,7 @@ #import #import #import +#include @implementation HBTSConversationPreferences { HBPreferences *_preferences; @@ -65,6 +66,14 @@ [_preferences registerPreferenceChangeBlock:callback]; } +- (void)_postReadReceiptNotification { + // if we do this in imagent, the callback for this notification can cause an infinite loop, so + // don’t post it in that case + if (!self._isInIMAgent) { + notify_post("ws.hbang.typestatus/ReadReceiptSettingsChanged"); + } +} + #pragma mark - Keys - (NSString *)_keyForChat:(IMChat *)chat type:(NSString *)type { @@ -101,6 +110,11 @@ return key ? [_preferences boolForKey:key default:self._readReceiptsEnabled] : self._readReceiptsEnabled; } +- (NSNumber *)readReceiptsEnabledForHandleAsNumber:(NSString *)handle { + NSString *key = [self _keyForHandle:handle type:@"Read"]; + return key ? [_preferences objectForKey:key] : nil; +} + #pragma mark - Setters - (void)setTypingNotificationsEnabled:(BOOL)enabled forChat:(IMChat *)chat { @@ -109,6 +123,7 @@ - (void)setReadReceiptsEnabled:(BOOL)enabled forChat:(IMChat *)chat { [_preferences setBool:enabled forKey:[self _keyForChat:chat type:@"Read"]]; + [self _postReadReceiptNotification]; } - (void)setTypingNotificationsEnabled:(BOOL)enabled forHandle:(NSString *)handle { @@ -117,6 +132,7 @@ - (void)setReadReceiptsEnabled:(BOOL)enabled forHandle:(NSString *)handle { [_preferences setBool:enabled forKey:[self _keyForHandle:handle type:@"Read"]]; + [self _postReadReceiptNotification]; } #pragma mark - Add/Remove diff --git a/messages/DetailsController.x b/messages/DetailsController.x index 039ede8..494122d 100644 --- a/messages/DetailsController.x +++ b/messages/DetailsController.x @@ -138,7 +138,7 @@ NSBundle *bundle; } - (void)readReceiptsSwitchValueChanged:(UISwitch *)sender { - // update ours as well + // update our read receipt enabled state [self._typeStatus_preferences setReadReceiptsEnabled:sender.on forChat:self.conversation.chat]; } diff --git a/relay/ReadReceiptMirror.x b/relay/ReadReceiptMirror.x index 8f9e9f0..81cbb42 100644 --- a/relay/ReadReceiptMirror.x +++ b/relay/ReadReceiptMirror.x @@ -7,13 +7,12 @@ - (BOOL)_readReceiptsEnabled; +- (NSNumber *)readReceiptsEnabledForHandleAsNumber:(NSString *)handle; + @end extern HBTSConversationPreferences *preferences; -// ugly workaround to avoid infinite loops -BOOL updating = YES; - void mirrorNativeReadReceiptPreferences() { // grab the chats, and the global state NSArray *chats = ((IMDChatRegistry *)[%c(IMDChatRegistry) sharedInstance]).chats; @@ -31,18 +30,19 @@ void mirrorNativeReadReceiptPreferences() { // get the native read receipt value, as well as our own NSNumber *value = chat.properties[@"EnableReadReceiptForChat"]; - BOOL ourValue = [preferences readReceiptsEnabledForHandle:handle]; + NSNumber *ourValue = [preferences readReceiptsEnabledForHandleAsNumber:handle]; // if it’s been set at least once before and is different from the global state if (value && value.boolValue != globalState) { // mirror it over to our side - updating = YES; [preferences setReadReceiptsEnabled:value.boolValue forHandle:handle]; - } else if (!value && ourValue != globalState) { - // if the value is nil, but we have a value that is different from the global state + } + + // if we have a value, and the system doesn’t or it differs from ours + if (ourValue && (!value || value.boolValue != ourValue.boolValue)) { // mirror it over to the other side [chat updateProperties:@{ - @"EnableReadReceiptForChat": @(ourValue), + @"EnableReadReceiptForChat": ourValue, @"EnableReadReceiptForChatVersionID": @1 }]; } @@ -52,9 +52,11 @@ void mirrorNativeReadReceiptPreferences() { %hook IMDChatRegistry - (void)loadChatsWithCompletionBlock:(void(^)())completion { - // override the completion block so we can execute our mirror logic immediately + // override the completion block so we can execute our mirror logic afterwards + __block void (^oldCompletion)() = [completion copy]; + void (^newCompletion)() = ^{ - completion(); + oldCompletion(); mirrorNativeReadReceiptPreferences(); }; @@ -64,11 +66,6 @@ void mirrorNativeReadReceiptPreferences() { %end %ctor { - [preferences registerPreferenceChangeBlock:^{ - if (updating) { - updating = NO; - } else { - mirrorNativeReadReceiptPreferences(); - } - }]; + // register a preference change block so we can execute another mirror + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, (CFNotificationCallback)mirrorNativeReadReceiptPreferences, CFSTR("ws.hbang.typestatus/ReadReceiptSettingsChanged"), NULL, kNilOptions); }