Immediate feedback on send + unread count badges.

pull/1/head
Frederic Jacobs 10 years ago
parent b5ba841c67
commit 83cc102f98

@ -20,7 +20,7 @@
if (self) {
_authorId = authorId;
_read = false;
_read = NO;
}
return self;
@ -35,7 +35,7 @@
if (self) {
_authorId = nil;
_read = false;
_read = NO;
}
return self;

@ -52,6 +52,8 @@ dispatch_queue_t sendingQueue() {
}
- (void)sendMessage:(TSOutgoingMessage*)message inThread:(TSThread*)thread{
[self saveMessage:message withState:TSOutgoingMessageStateAttemptingOut];
dispatch_async(sendingQueue(), ^{
if ([thread isKindOfClass:[TSGroupThread class]]) {
NSLog(@"Currently unsupported");
@ -85,7 +87,7 @@ dispatch_queue_t sendingQueue() {
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[recipient saveWithTransaction:transaction];
}];
[self handleMessageSent:message inThread:thread];
[self handleMessageSent:message];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
@ -116,18 +118,12 @@ dispatch_queue_t sendingQueue() {
}];
}];
} else{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message setMessageState:TSOutgoingMessageStateUnsent];
[message saveWithTransaction:transaction];
}];
[self saveMessage:message withState:TSOutgoingMessageStateUnsent];
}
}
- (void)handleMessageSent:(TSOutgoingMessage*)message inThread:(TSThread*)thread{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message setMessageState:TSOutgoingMessageStateSent];
[message saveWithTransaction:transaction];
}];
- (void)handleMessageSent:(TSOutgoingMessage*)message {
[self saveMessage:message withState:TSOutgoingMessageStateSent];
}
- (void)outgoingMessages:(TSOutgoingMessage*)message toRecipient:(TSRecipient*)recipient completion:(messagesQueue)sendMessages{
@ -211,6 +207,13 @@ dispatch_queue_t sendingQueue() {
return TSUnknownMessageType;
}
- (void)saveMessage:(TSOutgoingMessage*)message withState:(TSOutgoingMessageState)state{
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[message setMessageState:state];
[message saveWithTransaction:transaction];
}];
}
- (NSData*)plainTextForMessage:(TSOutgoingMessage*)message{
PushMessageContentBuilder *builder = [PushMessageContentBuilder new];

@ -12,11 +12,14 @@
extern NSString *TSInboxGroup;
extern NSString *TSArchiveGroup;
extern NSString *TSUnreadIncomingMessagesGroup;
extern NSString *TSThreadDatabaseViewExtensionName;
extern NSString *TSMessageDatabaseViewExtensionName;
extern NSString *TSUnreadDatabaseViewExtensionName;
+ (BOOL)registerThreadDatabaseView;
+ (BOOL)registerBuddyConversationDatabaseView;
+ (BOOL)registerUnreadDatabaseView;
@end

@ -11,18 +11,53 @@
#import <YapDatabase/YapDatabaseView.h>
#import "TSThread.h"
#import "TSIncomingMessage.h"
#import "TSInteraction.h"
#import "TSStorageManager.h"
#import "TSRecipient.h"
NSString *TSInboxGroup = @"TSInboxGroup";
NSString *TSArchiveGroup = @"TSArchiveGroup";
NSString *TSInboxGroup = @"TSInboxGroup";
NSString *TSArchiveGroup = @"TSArchiveGroup";
NSString *TSUnreadIncomingMessagesGroup = @"TSUnreadIncomingMessagesGroup";
NSString *TSThreadDatabaseViewExtensionName = @"TSThreadDatabaseViewExtensionName";
NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionName";
NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionName";
@implementation TSDatabaseView
+ (BOOL)registerUnreadDatabaseView {
YapDatabaseView *unreadView = [[TSStorageManager sharedManager].database registeredExtension:TSUnreadDatabaseViewExtensionName];
if (unreadView) {
return YES;
}
YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(NSString *collection, NSString *key, id object) {
if ([object isKindOfClass:[TSIncomingMessage class]]){
TSIncomingMessage *message = (TSIncomingMessage*)object;
if (message.read == NO){
return message.uniqueThreadId;
}
}
return nil;
}];
YapDatabaseViewSorting *viewSorting = [self messagesSorting];
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
options.isPersistent = YES;
options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSInteraction collection]]];
YapDatabaseView *view = [[YapDatabaseView alloc] initWithGrouping:viewGrouping
sorting:viewSorting
versionTag:@"1"
options:options];
return [[TSStorageManager sharedManager].database registerExtension:view withName:TSUnreadDatabaseViewExtensionName];
}
+ (BOOL)registerThreadDatabaseView {
YapDatabaseView *threadView = [[TSStorageManager sharedManager].database registeredExtension:TSThreadDatabaseViewExtensionName];
if (threadView) {
@ -69,17 +104,7 @@ NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionN
return nil;
}];
YapDatabaseViewSorting *viewSorting = [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(NSString *group, NSString *collection1, NSString *key1, id object1, NSString *collection2, NSString *key2, id object2) {
if ([object1 isKindOfClass:[TSInteraction class]] && [object2 isKindOfClass:[TSInteraction class]]) {
TSInteraction *message1 = (TSInteraction*)object1;
TSInteraction *message2 = (TSInteraction*)object2;
return [message1.date compare:message2.date];
}
return NSOrderedSame;
}];
YapDatabaseViewSorting *viewSorting = [self messagesSorting];
YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init];
options.isPersistent = YES;
@ -128,4 +153,18 @@ NSString *TSMessageDatabaseViewExtensionName = @"TSMessageDatabaseViewExtensionN
}
+ (YapDatabaseViewSorting*)messagesSorting {
return [YapDatabaseViewSorting withObjectBlock:^NSComparisonResult(NSString *group, NSString *collection1, NSString *key1, id object1, NSString *collection2, NSString *key2, id object2) {
if ([object1 isKindOfClass:[TSInteraction class]] && [object2 isKindOfClass:[TSInteraction class]]) {
TSInteraction *message1 = (TSInteraction*)object1;
TSInteraction *message2 = (TSInteraction*)object2;
return [message1.date compare:message2.date];
}
return NSOrderedSame;
}];
}
@end

@ -51,13 +51,13 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
};
_database = [[YapDatabase alloc] initWithPath:[self dbPath]
objectSerializer:NULL
objectDeserializer:NULL
metadataSerializer:NULL
metadataDeserializer:NULL
objectSanitizer:NULL
metadataSanitizer:NULL
options:options];
objectSerializer:NULL
objectDeserializer:NULL
metadataSerializer:NULL
metadataDeserializer:NULL
objectSanitizer:NULL
metadataSanitizer:NULL
options:options];
_dbConnection = self.newDatabaseConnection;
return self;
}
@ -65,6 +65,8 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
- (void)setupDatabase {
[TSDatabaseView registerThreadDatabaseView];
[TSDatabaseView registerBuddyConversationDatabaseView];
[TSDatabaseView registerUnreadDatabaseView];
[self.database registerExtension:[[YapDatabaseRelationship alloc] init] withName:@"TSRelationships"];
}
@ -73,16 +75,16 @@ static NSString * keychainDBPassAccount = @"TSDatabasePass";
*/
- (void)protectDatabaseFile{
NSDictionary *attrs = @{NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication};
NSError *error;
[NSFileManager.defaultManager setAttributes:attrs ofItemAtPath:[self dbPath] error:&error];
[[NSURL fileURLWithPath:[self dbPath]] setResourceValue:@YES
forKey:NSURLIsExcludedFromBackupKey
error:&error];
if (error) {
DDLogError(@"Error while removing log files from backup: %@", error.description);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:NSLocalizedString(@"WARNING", @"")

@ -33,6 +33,7 @@
#import <YapDatabase/YapDatabaseView.h>
#import "TSInteraction.h"
#import "TSMessageAdapter.h"
#import "TSIncomingMessage.h"
#import "TSMessagesManager+sendMessages.h"
#import "NSDate+millisecondTimeStamp.h"
@ -55,18 +56,21 @@ typedef enum : NSUInteger {
}
@property (nonatomic, retain) TSThread *thread;
@property (nonatomic, strong) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, strong) YapDatabaseConnection *editingDatabaseConnection;
@property (nonatomic, strong) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, strong) YapDatabaseViewMappings *messageMappings;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingMessageFailedImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *incomingBubbleImageData;
@property (nonatomic, retain) JSQMessagesBubbleImage *outgoingMessageFailedImageData;
@property (nonatomic, retain) NSTimer *readTimer;
@end
@implementation MessagesViewController
- (void)setupWithTSIdentifier:(NSString *)identifier{
[[TSStorageManager sharedManager].newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
self.thread = [TSContactThread threadWithContactId:identifier transaction:transaction];
}];
}
@ -77,17 +81,21 @@ typedef enum : NSUInteger {
- (void)viewDidLoad {
[super viewDidLoad];
[self markAllMessagesAsRead];
isGroupConversation = NO; // TODO: Support Group Conversations
[self initializeBubbles];
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[self.thread.uniqueId] view:TSMessageDatabaseViewExtensionName];
self.messageMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[self.thread.uniqueId]
view:TSMessageDatabaseViewExtensionName];
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.messageMappings updateWithTransaction:transaction];
}];
self.readTimer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(markAllMessagesAsRead) userInfo:nil repeats:YES];
[self initializeNavigationBar];
[self initializeCollectionViewLayout];
@ -95,13 +103,6 @@ typedef enum : NSUInteger {
self.senderDisplayName = ME_MESSAGE_IDENTIFIER
}
- (void)didPressBack{
[self dismissViewControllerAnimated:YES completion:^{
[self.navigationController.parentViewController.presentingViewController.navigationController pushViewController:self animated:NO];
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@ -156,6 +157,7 @@ typedef enum : NSUInteger {
-(void)showFingerprint
{
[self markAllMessagesAsRead];
[self performSegueWithIdentifier:@"fingerprintSegue" sender:self];
}
@ -271,8 +273,7 @@ typedef enum : NSUInteger {
-(JSQMessagesCollectionViewCell*)loadIncomingMessageCellForMessage:(id<JSQMessageData>)message atIndexPath:(NSIndexPath*)indexPath
{
JSQMessagesCollectionViewCell *cell = (JSQMessagesCollectionViewCell *)[super collectionView:self.collectionView cellForItemAtIndexPath:indexPath];
if (!message.isMediaMessage)
{
if (!message.isMediaMessage) {
cell.textView.textColor = [UIColor blackColor];
cell.textView.linkTextAttributes = @{ NSForegroundColorAttributeName : cell.textView.textColor,
NSUnderlineStyleAttributeName : @(NSUnderlineStyleSingle | NSUnderlinePatternSolid) };
@ -412,8 +413,7 @@ typedef enum : NSUInteger {
{
TSMessageAdapter * msg = [self messageAtIndexPath:indexPath];
if (msg.messageType == TSOutgoingMessageAdapter)
{
if (msg.messageType == TSOutgoingMessageAdapter) {
return 16.0f;
}
@ -565,7 +565,7 @@ typedef enum : NSUInteger {
NSError *err = NULL;
CMTime time = CMTimeMake(2, 1);
CGImageRef snapshotRef = [generate1 copyCGImageAtTime:time actualTime:NULL error:&err];
__unused UIImage *snapshot = [[UIImage alloc] initWithCGImage:snapshotRef];
__unused UIImage *snapshot = [[UIImage alloc] initWithCGImage:snapshotRef];
JSQVideoMediaItem * videoItem = [[JSQVideoMediaItem alloc] initWithFileURL:videoURL isReadyToPlay:YES];
JSQMessage * videoMessage = [JSQMessage messageWithSenderId:self.senderId
@ -591,8 +591,7 @@ typedef enum : NSUInteger {
#pragma mark Storage access
- (YapDatabaseConnection *)uiDatabaseConnection
{
- (YapDatabaseConnection*)uiDatabaseConnection {
NSAssert([NSThread isMainThread], @"Must access uiDatabaseConnection on main thread!");
if (!_uiDatabaseConnection) {
_uiDatabaseConnection = [[TSStorageManager sharedManager] newDatabaseConnection];
@ -605,6 +604,13 @@ typedef enum : NSUInteger {
return _uiDatabaseConnection;
}
- (YapDatabaseConnection*)editingDatabaseConnection {
if (!_editingDatabaseConnection) {
_editingDatabaseConnection = [[TSStorageManager sharedManager] newDatabaseConnection];
}
return _editingDatabaseConnection;
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
// Process the notification(s),
@ -617,7 +623,34 @@ typedef enum : NSUInteger {
rowChanges:&messageRowChanges
forNotifications:notifications
withMappings:self.messageMappings];
[self.collectionView reloadData];
for (YapDatabaseViewRowChange *rowChange in messageRowChanges)
{
switch (rowChange.type)
{
case YapDatabaseViewChangeDelete :
{
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath ]];
break;
}
case YapDatabaseViewChangeInsert :
{
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath ]];
break;
}
case YapDatabaseViewChangeMove :
{
[self.collectionView deleteItemsAtIndexPaths:@[ rowChange.indexPath]];
[self.collectionView insertItemsAtIndexPaths:@[ rowChange.newIndexPath]];
break;
}
case YapDatabaseViewChangeUpdate :
{
[self.collectionView reloadItemsAtIndexPaths:@[ rowChange.indexPath ]];
break;
}
}
}
[self finishReceivingMessage];
}
@ -685,4 +718,22 @@ typedef enum : NSUInteger {
}];
}
- (void)markAllMessagesAsRead {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSUnreadDatabaseViewExtensionName];
NSUInteger numberOfItemsInSection = [viewTransaction numberOfItemsInGroup:self.thread.uniqueId];
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *writeTransaction) {
for (NSUInteger i = 0; i < numberOfItemsInSection; i++) {
TSIncomingMessage *message = [viewTransaction objectAtIndex:i inGroup:self.thread.uniqueId];
message.read = YES;
[message saveWithTransaction:writeTransaction];
}
}];
}];
}
- (void)viewWillDisappear:(BOOL)animated{
[self.readTimer invalidate];
}
@end

@ -6,29 +6,58 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <YapDatabase/YapDatabaseViewMappings.h>
#import <YapDatabase/YapDatabaseViewTransaction.h>
#import "SignalTabBarController.h"
#import "TSAccountManager.h"
#import "TSDatabaseView.h"
#import "TSStorageManager.h"
@interface SignalTabBarController ()
@property YapDatabaseConnection *dbConnection;
@end
@implementation SignalTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (![TSAccountManager isRegistered]){
[self performSegueWithIdentifier:@"showSignupFlow" sender:self];
}
self.dbConnection = [TSStorageManager sharedManager].newDatabaseConnection;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:nil];
}
- (void)yapDatabaseModified:(NSNotification *)notification {
__block NSUInteger numberOfItems;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups];
}];
NSNumber *badgeNumber = [NSNumber numberWithUnsignedInteger:numberOfItems];
NSString *badgeValue = nil;
if (![badgeNumber isEqualToNumber:@0]) {
badgeValue = [badgeNumber stringValue];
}
[[self signalsItem] setBadgeValue:badgeValue];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:badgeNumber.integerValue];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (UITabBarItem*)signalsItem{
return self.tabBar.items[1];
}
@end

@ -60,7 +60,7 @@
NSString *contactId = ((TSContactThread*)thread).contactIdentifier;
adapter.senderId = contactId;
adapter.senderDisplayName = contactId;
adapter.messageType = TSIncomingMessageAdapter;
adapter.messageType = TSIncomingMessageAdapter;
} else {
adapter.senderId = ME_MESSAGE_IDENTIFIER;
adapter.senderDisplayName = @"Me";
@ -86,12 +86,12 @@
} else if ([interaction isKindOfClass:[TSInfoMessage class]]){
TSInfoMessage * infoMessage = (TSInfoMessage*)interaction;
adapter.infoMessageType = infoMessage.messageType;
adapter.messageBody = @"Placeholder for InfoMessage";
adapter.messageBody = infoMessage.description;
adapter.messageType = TSInfoMessageAdapter;
} else {
TSErrorMessage * errorMessage = (TSErrorMessage*)interaction;
adapter.infoMessageType = errorMessage.errorType;
adapter.messageBody = @"Placeholder for ErrorMessage";
adapter.messageBody = errorMessage.description;
adapter.messageType = TSErrorMessageAdapter;
}

Loading…
Cancel
Save