diff --git a/Yep/AppDelegate.swift b/Yep/AppDelegate.swift index 5c06575d..b9625130 100644 --- a/Yep/AppDelegate.swift +++ b/Yep/AppDelegate.swift @@ -43,7 +43,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { let directory: NSURL = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier(YepConfig.appGroupID)! let realmPath = directory.URLByAppendingPathComponent("db.realm").path! - return Realm.Configuration(path: realmPath, schemaVersion: 17, migrationBlock: { migration, oldSchemaVersion in + return Realm.Configuration(path: realmPath, schemaVersion: 18, migrationBlock: { migration, oldSchemaVersion in }) } diff --git a/Yep/Realm/Models.swift b/Yep/Realm/Models.swift index 87f1180e..aff0e74f 100644 --- a/Yep/Realm/Models.swift +++ b/Yep/Realm/Models.swift @@ -511,6 +511,14 @@ class Message: Object { dynamic var mediaType: Int = MessageMediaType.Text.rawValue dynamic var textContent: String = "" + var textContentToShow: String { + if deletedByCreator { + return NSLocalizedString("Deleted by creator.", comment: "") + } else { + return textContent + } + } + dynamic var coordinate: Coordinate? dynamic var attachmentURLString: String = "" @@ -550,7 +558,8 @@ class Message: Object { dynamic var sendState: Int = MessageSendState.NotSend.rawValue dynamic var readed: Bool = false dynamic var mediaPlayed: Bool = false // 音频播放过,图片查看过等 - dynamic var deleted: Bool = false // 标记已被删除,删除对方消息,使之不再显示 + dynamic var hidden: Bool = false // 隐藏对方消息,使之不再显示 + dynamic var deletedByCreator: Bool = false dynamic var fromFriend: User? dynamic var conversation: Conversation? @@ -611,6 +620,25 @@ class Message: Object { break // TODO: if have other message media need to delete } } + + func deleteInRealm(realm: Realm) { + deleteAttachmentInRealm(realm) + realm.delete(self) + } + + func updateForDeletedFromServerInRealm(realm: Realm) { + + deletedByCreator = true + + // 删除附件 + deleteAttachmentInRealm(realm) + + // 再将其变为文字消息 + sendState = MessageSendState.Read.rawValue + readed = true + textContent = "" + mediaType = MessageMediaType.Text.rawValue + } } class Draft: Object { @@ -708,6 +736,10 @@ class Conversation: Object { } dynamic var unreadMessagesCount: Int = 0 + + var latestValidMessage: Message? { + return messages.filter({ ($0.hidden == false) && ($0.deletedByCreator == false && ($0.mediaType != MessageMediaType.SectionDate.rawValue)) }).sort({ $0.createdUnixTime > $1.createdUnixTime }).first + } } // MARK: Feed @@ -1007,7 +1039,7 @@ func countOfUnreadMessagesInConversation(conversation: Conversation) -> Int { }).count } -func latestMessageInRealm(realm: Realm, withConversationType conversationType: ConversationType) -> Message? { +func latestValidMessageInRealm(realm: Realm, withConversationType conversationType: ConversationType) -> Message? { // let predicate = NSPredicate(format: "fromFriend != nil AND conversation != nil AND conversation.type = %d", conversationType.rawValue) // return realm.objects(Message).filter(predicate).sorted("updatedUnixTime", ascending: false).first @@ -1015,26 +1047,30 @@ func latestMessageInRealm(realm: Realm, withConversationType conversationType: C switch conversationType { case .OneToOne: - let predicate = NSPredicate(format: "fromFriend != nil AND conversation != nil AND conversation.type = %d", conversationType.rawValue) + let predicate = NSPredicate(format: "hidden = false AND deletedByCreator = false AND fromFriend != nil AND conversation != nil AND conversation.type = %d", conversationType.rawValue) return realm.objects(Message).filter(predicate).sorted("updatedUnixTime", ascending: false).first case .Group: let predicate = NSPredicate(format: "withGroup != nil AND withGroup.includeMe = true") - return realm.objects(Conversation).filter(predicate).sorted("updatedUnixTime", ascending: false).first?.messages.sort({ $0.createdUnixTime > $1.createdUnixTime }).first + let messages: [Message]? = realm.objects(Conversation).filter(predicate).sorted("updatedUnixTime", ascending: false).first?.messages.sort({ $0.createdUnixTime > $1.createdUnixTime }) + + return messages?.filter({ ($0.hidden == false) && ($0.deletedByCreator == false) }).first } } -func latestUnreadMessageInRealm(realm: Realm, withConversationType conversationType: ConversationType) -> Message? { +func latestUnreadValidMessageInRealm(realm: Realm, withConversationType conversationType: ConversationType) -> Message? { switch conversationType { case .OneToOne: - let predicate = NSPredicate(format: "readed = false AND fromFriend != nil AND conversation != nil AND conversation.type = %d", conversationType.rawValue) + let predicate = NSPredicate(format: "readed = false AND hidden = false AND deletedByCreator = false AND fromFriend != nil AND conversation != nil AND conversation.type = %d", conversationType.rawValue) return realm.objects(Message).filter(predicate).sorted("updatedUnixTime", ascending: false).first case .Group: let predicate = NSPredicate(format: "withGroup != nil AND withGroup.includeMe = true") - return realm.objects(Conversation).filter(predicate).sorted("updatedUnixTime", ascending: false).first?.messages.filter({ $0.readed == false && $0.fromFriend?.userID != YepUserDefaults.userID.value }).sort({ $0.createdUnixTime > $1.createdUnixTime }).first + let messages: [Message]? = realm.objects(Conversation).filter(predicate).sorted("updatedUnixTime", ascending: false).first?.messages.filter({ $0.readed == false && $0.fromFriend?.userID != YepUserDefaults.userID.value }).sort({ $0.createdUnixTime > $1.createdUnixTime }) + + return messages?.filter({ ($0.hidden == false) && ($0.deletedByCreator == false) }).first } } @@ -1307,25 +1343,28 @@ func unReadMessagesOfConversation(conversation: Conversation, inRealm realm: Rea */ func messagesOfConversation(conversation: Conversation, inRealm realm: Realm) -> Results { - let predicate = NSPredicate(format: "conversation = %@ AND deleted = false", argumentArray: [conversation]) + let predicate = NSPredicate(format: "conversation = %@ AND hidden = false", argumentArray: [conversation]) let messages = realm.objects(Message).filter(predicate).sorted("createdUnixTime", ascending: true) return messages } -func deleteMessage(message: Message, inRealm realm: Realm) { - realm.delete(message) -} - func handleMessageDeletedFromServer(messageID messageID: String) { guard let realm = try? Realm(), - message = messageWithMessageID(messageID, inRealm: realm), - conversation = message.conversation + message = messageWithMessageID(messageID, inRealm: realm) + //conversation = message.conversation else { return } + let _ = try? realm.write { + message.updateForDeletedFromServerInRealm(realm) + } + + let messageIDs: [String] = [message.messageID] + + /* let messages = messagesOfConversation(conversation, inRealm: realm) var sectionDateMessage: Message? @@ -1347,9 +1386,10 @@ func handleMessageDeletedFromServer(messageID messageID: String) { message.deleteAttachmentInRealm(realm) realm.delete(message) } + */ dispatch_async(dispatch_get_main_queue()) { - NSNotificationCenter.defaultCenter().postNotificationName(YepConfig.Notification.deletedMessages, object: nil) + NSNotificationCenter.defaultCenter().postNotificationName(YepConfig.Notification.deletedMessages, object: ["messageIDs": messageIDs]) } } @@ -1562,11 +1602,11 @@ func updateUserWithUserID(userID: String, useUserInfo userInfo: JSONDictionary, // MARK: Delete -private func clearMessagesOfConversation(conversation: Conversation, inRealm realm: Realm, keepDeletedMessages: Bool) { +private func clearMessagesOfConversation(conversation: Conversation, inRealm realm: Realm, keepHiddenMessages: Bool) { let messages: [Message] - if keepDeletedMessages { - messages = conversation.messages.filter({ $0.deleted == false }) + if keepHiddenMessages { + messages = conversation.messages.filter({ $0.hidden == false }) } else { messages = conversation.messages } @@ -1582,7 +1622,7 @@ private func clearMessagesOfConversation(conversation: Conversation, inRealm rea func deleteConversation(conversation: Conversation, inRealm realm: Realm, needLeaveGroup: Bool = true, afterLeaveGroup: (() -> Void)? = nil) { - clearMessagesOfConversation(conversation, inRealm: realm, keepDeletedMessages: false) + clearMessagesOfConversation(conversation, inRealm: realm, keepHiddenMessages: false) // delete conversation, finally @@ -1623,7 +1663,7 @@ func tryDeleteOrClearHistoryOfConversation(conversation: Conversation, inViewCon let clearMessages: () -> Void = { realm.beginWrite() - clearMessagesOfConversation(conversation, inRealm: realm, keepDeletedMessages: true) + clearMessagesOfConversation(conversation, inRealm: realm, keepHiddenMessages: true) let _ = try? realm.commitWrite() } diff --git a/Yep/Services/SocialWorkService.swift b/Yep/Services/SocialWorkService.swift index cabaffd2..5523e3f9 100644 --- a/Yep/Services/SocialWorkService.swift +++ b/Yep/Services/SocialWorkService.swift @@ -449,7 +449,7 @@ func syncSocialWorksToMessagesForYepTeam() { return messageIDs } else { - deleteMessage(message, inRealm: realm) + message.deleteInRealm(realm) } } diff --git a/Yep/Services/YepServiceSync.swift b/Yep/Services/YepServiceSync.swift index f4ea34e0..1c565050 100644 --- a/Yep/Services/YepServiceSync.swift +++ b/Yep/Services/YepServiceSync.swift @@ -827,10 +827,17 @@ func syncMessagesReadStatus() { func recordMessageWithMessageID(messageID: String, detailInfo messageInfo: JSONDictionary, inRealm realm: Realm) { - println("messageInfo: \(messageInfo)") + //println("messageInfo: \(messageInfo)") + + let deleted = (messageInfo["deleted"] as? Bool) ?? false if let message = messageWithMessageID(messageID, inRealm: realm) { + guard !deleted else { + message.updateForDeletedFromServerInRealm(realm) + return + } + if let user = message.fromFriend where user.userID == YepUserDefaults.userID.value { message.sendState = MessageSendState.Read.rawValue } @@ -910,11 +917,26 @@ func recordMessageWithMessageID(messageID: String, detailInfo messageInfo: JSOND } func syncMessageWithMessageInfo(messageInfo: JSONDictionary, messageAge: MessageAge, inRealm realm: Realm, andDoFurtherAction furtherAction: ((messageIDs: [String]) -> Void)? ) { - + if let messageID = messageInfo["id"] as? String { var message = messageWithMessageID(messageID, inRealm: realm) + // 如果消息被删除,且的发送者是自己,不同步且删除本地已有的 + let deleted = (messageInfo["deleted"] as? Bool) ?? false + if deleted { + if let senderInfo = messageInfo["sender"] as? JSONDictionary, senderID = senderInfo["id"] as? String { + if senderID == YepUserDefaults.userID.value { + if let message = message { + message.deleteAttachmentInRealm(realm) + realm.delete(message) + } + + return + } + } + } + if message == nil { let newMessage = Message() newMessage.messageID = messageID @@ -1111,7 +1133,7 @@ func syncMessageWithMessageInfo(messageInfo: JSONDictionary, messageAge: Message } } else { - deleteMessage(message, inRealm: realm) + message.deleteInRealm(realm) } } } diff --git a/Yep/ViewControllers/Conversation/ConversationViewController.swift b/Yep/ViewControllers/Conversation/ConversationViewController.swift index a1818a72..569704a0 100644 --- a/Yep/ViewControllers/Conversation/ConversationViewController.swift +++ b/Yep/ViewControllers/Conversation/ConversationViewController.swift @@ -1800,7 +1800,8 @@ class ConversationViewController: BaseViewController { switch message.mediaType { case MessageMediaType.Text.rawValue: - let rect = message.textContent.boundingRectWithSize(CGSize(width: messageTextLabelMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.ChatCell.textAttributes, context: nil) + + let rect = message.textContentToShow.boundingRectWithSize(CGSize(width: messageTextLabelMaxWidth, height: CGFloat(FLT_MAX)), options: [.UsesLineFragmentOrigin, .UsesFontLeading], attributes: YepConfig.ChatCell.textAttributes, context: nil) height = max(ceil(rect.height) + (11 * 2), YepConfig.chatCellAvatarSize()) @@ -1871,6 +1872,9 @@ class ConversationViewController: BaseViewController { return height } + private func clearHeightOfMessageWithKey(key: String) { + messageHeights[key] = nil + } private var textContentLabelWidths = [String: CGFloat]() private func textContentLabelWidthOfMessage(message: Message) -> CGFloat { @@ -2497,7 +2501,17 @@ class ConversationViewController: BaseViewController { @objc private func handleDeletedMessagesNotification(notification: NSNotification) { - reloadConversationCollectionView() + defer { + reloadConversationCollectionView() + } + + guard let info = notification.object as? [String: AnyObject], messageIDs = info["messageIDs"] as? [String] else { + return + } + + messageIDs.forEach { + clearHeightOfMessageWithKey($0) + } } // App 进入前台时,根据通知插入处于后台状态时收到的消息 @@ -3347,7 +3361,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi }) } else { - message.deleted = true + message.hidden = true } } @@ -3375,7 +3389,7 @@ extension ConversationViewController: UICollectionViewDataSource, UICollectionVi }) } else { - message.deleted = true + message.hidden = true } } diff --git a/Yep/ViewControllers/Conversations/ConversationsViewController.swift b/Yep/ViewControllers/Conversations/ConversationsViewController.swift index 816da20a..dbf15c22 100644 --- a/Yep/ViewControllers/Conversations/ConversationsViewController.swift +++ b/Yep/ViewControllers/Conversations/ConversationsViewController.swift @@ -369,9 +369,9 @@ extension ConversationsViewController: UITableViewDataSource, UITableViewDelegat cell.haveGroupUnreadMessages = countOfUnreadMessagesInRealm(realm, withConversationType: ConversationType.Group) > 0 // 先找最新且未读的消息 - let latestUnreadMessage = latestUnreadMessageInRealm(realm, withConversationType: ConversationType.Group) + let latestUnreadMessage = latestUnreadValidMessageInRealm(realm, withConversationType: ConversationType.Group) // 找不到就找最新的消息 - if let latestMessage = (latestUnreadMessage ?? latestMessageInRealm(realm, withConversationType: ConversationType.Group)) { + if let latestMessage = (latestUnreadMessage ?? latestValidMessageInRealm(realm, withConversationType: ConversationType.Group)) { if let mediaType = MessageMediaType(rawValue: latestMessage.mediaType), placeholder = mediaType.placeholder { cell.chatLabel.text = placeholder diff --git a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift index 6bb38703..c0cc8a63 100644 --- a/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift +++ b/Yep/Views/Cells/ChatLeftText/ChatLeftTextCell.swift @@ -64,7 +64,14 @@ class ChatLeftTextCell: ChatBaseCell { self.user = message.fromFriend - textContentTextView.text = message.textContent + textContentTextView.text = message.textContentToShow + + if message.deletedByCreator { + textContentTextView.textColor = UIColor.lightGrayColor() + } else { + textContentTextView.textColor = UIColor.blackColor() + } + //textContentTextView.attributedText = NSAttributedString(string: message.textContent, attributes: textAttributes) //textContentTextView.textAlignment = textContentLabelWidth < YepConfig.minMessageTextLabelWidth ? .Center : .Left diff --git a/Yep/Views/Cells/Conversation/ConversationCell.swift b/Yep/Views/Cells/Conversation/ConversationCell.swift index 2f2f242b..4937cb94 100644 --- a/Yep/Views/Cells/Conversation/ConversationCell.swift +++ b/Yep/Views/Cells/Conversation/ConversationCell.swift @@ -69,15 +69,15 @@ class ConversationCell: UITableViewCell { func updateInfoLabels() { - if let latestMessage = messagesInConversation(conversation).last { + if let latestValidMessage = conversation.latestValidMessage { - if let mediaType = MessageMediaType(rawValue: latestMessage.mediaType), placeholder = mediaType.placeholder { + if let mediaType = MessageMediaType(rawValue: latestValidMessage.mediaType), placeholder = mediaType.placeholder { self.chatLabel.text = placeholder } else { - self.chatLabel.text = latestMessage.textContent + self.chatLabel.text = latestValidMessage.textContent } - let createdAt = NSDate(timeIntervalSince1970: latestMessage.createdUnixTime) + let createdAt = NSDate(timeIntervalSince1970: latestValidMessage.createdUnixTime) self.timeAgoLabel.text = createdAt.timeAgo } else { diff --git a/Yep/Views/Cells/FeedConversation/FeedConversationCell.swift b/Yep/Views/Cells/FeedConversation/FeedConversationCell.swift index 4b814b06..75cc2d1b 100644 --- a/Yep/Views/Cells/FeedConversation/FeedConversationCell.swift +++ b/Yep/Views/Cells/FeedConversation/FeedConversationCell.swift @@ -68,12 +68,12 @@ class FeedConversationCell: UITableViewCell { }) mediaView.setImagesWithAttachments(attachments) - if let latestMessage = messagesInConversation(conversation).last { + if let latestValidMessage = conversation.latestValidMessage { - if let mediaType = MessageMediaType(rawValue: latestMessage.mediaType), placeholder = mediaType.placeholder { + if let mediaType = MessageMediaType(rawValue: latestValidMessage.mediaType), placeholder = mediaType.placeholder { self.chatLabel.text = placeholder } else { - self.chatLabel.text = latestMessage.nicknameWithTextContent + self.chatLabel.text = latestValidMessage.nicknameWithTextContent } } else { diff --git a/Yep/zh-Hans.lproj/Localizable.strings b/Yep/zh-Hans.lproj/Localizable.strings index c3bb86dd..8595eff8 100644 --- a/Yep/zh-Hans.lproj/Localizable.strings +++ b/Yep/zh-Hans.lproj/Localizable.strings @@ -726,3 +726,5 @@ "Hide" = "隐藏"; +"Deleted by creator." = "被创建者删除。"; +