mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 03:09:56 +00:00
Improve feedback handling
- Messages deleted on the server will be internally marked as being archived - Pre-send a token for each new message for easier identification and detection of double sending
This commit is contained in:
parent
c8c1ad8e10
commit
d884936029
@ -45,6 +45,7 @@
|
||||
#define kBITFeedbackToken @"HockeyFeedbackToken"
|
||||
#define kBITFeedbackName @"HockeyFeedbackName"
|
||||
#define kBITFeedbackEmail @"HockeyFeedbackEmail"
|
||||
#define kBITFeedbackLastMessageID @"HockeyFeedbackLastMessageID"
|
||||
|
||||
|
||||
@implementation BITFeedbackManager {
|
||||
@ -144,6 +145,20 @@
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
- (NSString *)uuidString {
|
||||
CFUUIDRef theToken = CFUUIDCreate(NULL);
|
||||
CFStringRef stringUUID = CFUUIDCreateString(NULL, theToken);
|
||||
CFRelease(theToken);
|
||||
|
||||
return [(NSString *)stringUUID autorelease];
|
||||
}
|
||||
|
||||
- (NSString *)uuidAsLowerCaseAndShortened {
|
||||
return [[[self uuidString] lowercaseString] stringByReplacingOccurrencesOfString:@"-" withString:@""];
|
||||
}
|
||||
|
||||
#pragma mark - Feedback Modal UI
|
||||
|
||||
- (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal {
|
||||
@ -332,13 +347,18 @@
|
||||
NSDate *date1 = [obj1 date];
|
||||
NSDate *date2 = [obj2 date];
|
||||
|
||||
// not send and send in progress messages on top, sorted by date
|
||||
// not send, in conflict and send in progress messages on top, sorted by date
|
||||
// read and unread on bottom, sorted by date
|
||||
// archived on the very bottom
|
||||
|
||||
if ([obj1 status] >= BITFeedbackMessageStatusSendInProgress && [obj2 status] < BITFeedbackMessageStatusSendInProgress) {
|
||||
return NSOrderedAscending;
|
||||
} else if ([obj1 status] < BITFeedbackMessageStatusSendInProgress && [obj2 status] >= BITFeedbackMessageStatusSendInProgress) {
|
||||
return NSOrderedDescending;
|
||||
} else if ([obj1 status] == BITFeedbackMessageStatusArchived && [obj2 status] < BITFeedbackMessageStatusArchived) {
|
||||
return NSOrderedDescending;
|
||||
} else if ([obj1 status] < BITFeedbackMessageStatusArchived && [obj2 status] == BITFeedbackMessageStatusArchived) {
|
||||
return NSOrderedAscending;
|
||||
} else {
|
||||
return (NSInteger)[date2 compare:date1];
|
||||
}
|
||||
@ -390,6 +410,14 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)markSendInProgressMessagesAsInConflict {
|
||||
// make sure message that may have not been send successfully, get back into the right state to be send again
|
||||
[_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) {
|
||||
if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress)
|
||||
[(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusInConflict];
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - User
|
||||
|
||||
@ -479,19 +507,21 @@
|
||||
BITFeedbackMessage *thisMessage = [self messageWithID:messageID];
|
||||
if (!thisMessage) {
|
||||
// check if this is a message that was sent right now
|
||||
__block BITFeedbackMessage *matchingSendInProgressMessage = nil;
|
||||
__block BITFeedbackMessage *matchingSendInProgressOrInConflictMessage = nil;
|
||||
|
||||
// TODO: match messages in state conflict
|
||||
|
||||
[messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) {
|
||||
if ([[(NSDictionary *)objMessage objectForKey:@"text"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage text]]) {
|
||||
matchingSendInProgressMessage = objSendInProgressMessage;
|
||||
if ([[(NSDictionary *)objMessage objectForKey:@"token"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage token]]) {
|
||||
matchingSendInProgressOrInConflictMessage = objSendInProgressMessage;
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
|
||||
if (matchingSendInProgressMessage) {
|
||||
matchingSendInProgressMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]];
|
||||
matchingSendInProgressMessage.id = messageID;
|
||||
matchingSendInProgressMessage.status = BITFeedbackMessageStatusRead;
|
||||
if (matchingSendInProgressOrInConflictMessage) {
|
||||
matchingSendInProgressOrInConflictMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]];
|
||||
matchingSendInProgressOrInConflictMessage.id = messageID;
|
||||
matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead;
|
||||
} else {
|
||||
BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease];
|
||||
message.text = [(NSDictionary *)objMessage objectForKey:@"text"];
|
||||
@ -554,7 +584,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
- (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSString *)text completionHandler:(void (^)(NSError *err))completionHandler {
|
||||
- (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BITFeedbackMessage *)message completionHandler:(void (^)(NSError *err))completionHandler {
|
||||
NSString *boundary = @"----FOO";
|
||||
|
||||
_networkRequestInProgress = YES;
|
||||
@ -582,7 +612,7 @@
|
||||
[request setValue:@"Hockey/iOS" forHTTPHeaderField:@"User-Agent"];
|
||||
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
|
||||
|
||||
if (text) {
|
||||
if (message) {
|
||||
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
|
||||
[request setValue:contentType forHTTPHeaderField:@"Content-type"];
|
||||
|
||||
@ -593,7 +623,8 @@
|
||||
[postBody appendData:[self appendPostValue:[self getDevicePlatform] forKey:@"model"]];
|
||||
[postBody appendData:[self appendPostValue:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0] forKey:@"lang"]];
|
||||
[postBody appendData:[self appendPostValue:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:@"bundle_version"]];
|
||||
[postBody appendData:[self appendPostValue:text forKey:@"text"]];
|
||||
[postBody appendData:[self appendPostValue:[message text] forKey:@"text"]];
|
||||
[postBody appendData:[self appendPostValue:[message token] forKey:@"message_token"]];
|
||||
|
||||
if (self.userName) {
|
||||
[postBody appendData:[self appendPostValue:self.userName forKey:@"name"]];
|
||||
@ -619,6 +650,28 @@
|
||||
if (statusCode == 404) {
|
||||
// thread has been deleted, we archive it
|
||||
[self updateMessageListFromResponse:nil];
|
||||
} else if (statusCode == 409) {
|
||||
// we submitted a message that is already on the server, mark it as being in conflict and resolve it with another fetch
|
||||
|
||||
if (!self.token) {
|
||||
// set the token to the first message token, since this is identical
|
||||
__block NSString *token = nil;
|
||||
|
||||
[_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) {
|
||||
if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress) {
|
||||
token = [(BITFeedbackMessage *)objMessage token];
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
|
||||
if (token) {
|
||||
self.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
[self markSendInProgressMessagesAsInConflict];
|
||||
[self saveMessages];
|
||||
[self performSelector:@selector(fetchMessageUpdates) withObject:nil afterDelay:0.2];
|
||||
} else if ([responseData length]) {
|
||||
NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease];
|
||||
BITHockeyLog(@"INFO: Received API response: %@", responseString);
|
||||
@ -662,7 +715,7 @@
|
||||
}
|
||||
|
||||
[self sendNetworkRequestWithHTTPMethod:@"GET"
|
||||
withText:nil
|
||||
withMessage:nil
|
||||
completionHandler:^(NSError *err){
|
||||
// inform the UI to update its data in case the list is already showing
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil];
|
||||
@ -696,7 +749,7 @@
|
||||
}
|
||||
|
||||
[self sendNetworkRequestWithHTTPMethod:httpMethod
|
||||
withText:[messageToSend text]
|
||||
withMessage:messageToSend
|
||||
completionHandler:^(NSError *err){
|
||||
if (err) {
|
||||
[self markSendInProgressMessagesAsPending];
|
||||
@ -714,6 +767,7 @@
|
||||
BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease];
|
||||
message.text = text;
|
||||
[message setStatus:BITFeedbackMessageStatusSendPending];
|
||||
[message setToken:[self uuidAsLowerCaseAndShortened]];
|
||||
[message setUserMessage:YES];
|
||||
|
||||
[_feedbackList addObject:message];
|
||||
|
||||
@ -32,14 +32,16 @@
|
||||
typedef enum {
|
||||
// default and new messages from SDK per default
|
||||
BITFeedbackMessageStatusSendPending = 0,
|
||||
// message is in conflict, happens if the message is already stored on the server and tried sending it again
|
||||
BITFeedbackMessageStatusInConflict = 1,
|
||||
// sending of message is in progress
|
||||
BITFeedbackMessageStatusSendInProgress = 1,
|
||||
BITFeedbackMessageStatusSendInProgress = 2,
|
||||
// new messages from server
|
||||
BITFeedbackMessageStatusUnread = 2,
|
||||
BITFeedbackMessageStatusUnread = 3,
|
||||
// messages from server once read and new local messages once successful send from SDK
|
||||
BITFeedbackMessageStatusRead = 3,
|
||||
BITFeedbackMessageStatusRead = 4,
|
||||
// message is archived, happens if the thread is deleted from the server
|
||||
BITFeedbackMessageStatusArchived = 4
|
||||
BITFeedbackMessageStatusArchived = 5
|
||||
} BITFeedbackMessageStatus;
|
||||
|
||||
@interface BITFeedbackMessage : NSObject {
|
||||
@ -50,6 +52,7 @@ typedef enum {
|
||||
@property (nonatomic, copy) NSString *email;
|
||||
@property (nonatomic, copy) NSDate *date;
|
||||
@property (nonatomic, copy) NSNumber *id;
|
||||
@property (nonatomic, copy) NSString *token;
|
||||
@property (nonatomic) BITFeedbackMessageStatus status;
|
||||
@property (nonatomic) BOOL userMessage;
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@
|
||||
_name = nil;
|
||||
_email = nil;
|
||||
_date = nil;
|
||||
_token = nil;
|
||||
_id = [[NSNumber alloc] initWithInteger:0];
|
||||
_status = BITFeedbackMessageStatusSendPending;
|
||||
_userMessage = NO;
|
||||
@ -53,6 +54,7 @@
|
||||
[_email release], _email = nil;
|
||||
[_date release], _date = nil;
|
||||
[_id release], _id = nil;
|
||||
[_token release], _token = nil;
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
@ -68,6 +70,7 @@
|
||||
[encoder encodeObject:self.id forKey:@"id"];
|
||||
[encoder encodeInteger:self.status forKey:@"status"];
|
||||
[encoder encodeBool:self.userMessage forKey:@"userMessage"];
|
||||
[encoder encodeObject:self.token forKey:@"token"];
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
@ -79,6 +82,7 @@
|
||||
self.id = [decoder decodeObjectForKey:@"id"];
|
||||
self.status = [decoder decodeIntegerForKey:@"status"];
|
||||
self.userMessage = [decoder decodeBoolForKey:@"userMessage"];
|
||||
self.token = [decoder decodeObjectForKey:@"token"];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user