diff --git a/src/Contacts/TSThread.h b/src/Contacts/TSThread.h index 06e21fdbb..6ac4e0469 100644 --- a/src/Contacts/TSThread.h +++ b/src/Contacts/TSThread.h @@ -1,5 +1,6 @@ -// Created by Frederic Jacobs on 16/11/14. -// Copyright (c) 2014 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "TSYapDatabaseObject.h" #import @@ -145,6 +146,32 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)setDraft:(NSString *)draftString transaction:(YapDatabaseReadWriteTransaction *)transaction; +@property (atomic, readonly) BOOL isMuted; +@property (atomic, readonly) NSDate *mutedUntilDate; + +// This model may be updated from many threads. We don't want to save +// our local copy (this instance) since it may be out of date. Instead, we +// use these "updateWith..." methods to: +// +// a) Update a property of this instance. +// b) Load an up-to-date instance of this model from from the data store. +// c) Update and save that fresh instance. +// d) If this instance hasn't yet been saved, save this local instance. +// +// After "updateWith...": +// +// a) An updated copy of this instance will always have been saved in the +// data store. +// b) The local property on this instance will always have been updated. +// c) Other properties on this instance may be out of date. +// +// All mutable properties of this class have been made read-only to +// prevent accidentally modifying them directly. +// +// This isn't a perfect arrangement, but in practice this will prevent +// data loss and will resolve all known issues. +- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate; + @end NS_ASSUME_NONNULL_END diff --git a/src/Contacts/TSThread.m b/src/Contacts/TSThread.m index cd2b5ac71..3cbf840a7 100644 --- a/src/Contacts/TSThread.m +++ b/src/Contacts/TSThread.m @@ -10,15 +10,18 @@ #import "TSInvalidIdentityKeyReceivingErrorMessage.h" #import "TSOutgoingMessage.h" #import "TSStorageManager.h" +#import +#import NS_ASSUME_NONNULL_BEGIN @interface TSThread () -@property (nonatomic, retain) NSDate *creationDate; +@property (nonatomic) NSDate *creationDate; @property (nonatomic, copy) NSDate *archivalDate; -@property (nonatomic, retain) NSDate *lastMessageDate; +@property (nonatomic) NSDate *lastMessageDate; @property (nonatomic, copy) NSString *messageDraft; +@property (atomic) NSDate *mutedUntilDate; - (TSInteraction *)lastInteraction; @@ -295,6 +298,46 @@ NS_ASSUME_NONNULL_BEGIN [thread saveWithTransaction:transaction]; } +#pragma mark - Muted + +- (BOOL)isMuted +{ + NSDate *mutedUntilDate = self.mutedUntilDate; + NSDate *now = [NSDate date]; + return (mutedUntilDate != nil && + [mutedUntilDate timeIntervalSinceDate:now] > 0); +} + +// This method does the work for the "updateWith..." methods. Please see +// the header for a discussion of those methods. +- (void)applyChangeToSelfAndLatestThread:(YapDatabaseReadWriteTransaction *)transaction + changeBlock:(void (^)(TSThread *))changeBlock +{ + OWSAssert(transaction); + + changeBlock(self); + + NSString *collection = [[self class] collection]; + TSThread *latestInstance = [transaction objectForKey:self.uniqueId inCollection:collection]; + if (latestInstance) { + changeBlock(latestInstance); + [latestInstance saveWithTransaction:transaction]; + } else { + // This message has not yet been saved. + [self saveWithTransaction:transaction]; + } +} + +- (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate +{ + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + [self applyChangeToSelfAndLatestThread:transaction + changeBlock:^(TSThread *thread) { + [thread setMutedUntilDate:mutedUntilDate]; + }]; + }]; +} + #pragma mark - Logging + (NSString *)tag