Skip to content

Commit

Permalink
Clear or delete conversation with work
Browse files Browse the repository at this point in the history
  • Loading branch information
wuyuehyang committed Jun 8, 2022
1 parent 2a6e3f6 commit 461edb1
Show file tree
Hide file tree
Showing 22 changed files with 247 additions and 212 deletions.
4 changes: 4 additions & 0 deletions Mixin.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,7 @@
947E0659279867870002669B /* PINIteratorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947E0658279867870002669B /* PINIteratorTest.swift */; };
947F4AD625866D6C00B0A5F9 /* InitializeFTSJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947F4AD525866D6C00B0A5F9 /* InitializeFTSJob.swift */; };
94812DDA26E082C400213F79 /* mixin_condensed.otf in Resources */ = {isa = PBXBuildFile; fileRef = 94812DD926E082C400213F79 /* mixin_condensed.otf */; };
948983B1284E66C00065DC5D /* ConversationCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 948983B0284E66C00065DC5D /* ConversationCleaner.swift */; };
9489E3A025C5B150000319F8 /* AcknowledgementsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9489E39F25C5B150000319F8 /* AcknowledgementsViewController.swift */; };
9492285F25DFB7D60000A19F /* MinimizedPlaylistViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9492285E25DFB7D60000A19F /* MinimizedPlaylistViewController.swift */; };
9492286425DFB7EF0000A19F /* MinimizedPlaylistView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9492286325DFB7EF0000A19F /* MinimizedPlaylistView.xib */; };
Expand Down Expand Up @@ -1659,6 +1660,7 @@
947F4AD525866D6C00B0A5F9 /* InitializeFTSJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializeFTSJob.swift; sourceTree = "<group>"; };
94812DD926E082C400213F79 /* mixin_condensed.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = mixin_condensed.otf; sourceTree = "<group>"; };
94841CC72797D89500B3593B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
948983B0284E66C00065DC5D /* ConversationCleaner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationCleaner.swift; sourceTree = "<group>"; };
9489E39F25C5B150000319F8 /* AcknowledgementsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AcknowledgementsViewController.swift; sourceTree = "<group>"; };
9492285E25DFB7D60000A19F /* MinimizedPlaylistViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MinimizedPlaylistViewController.swift; sourceTree = "<group>"; };
9492286325DFB7EF0000A19F /* MinimizedPlaylistView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MinimizedPlaylistView.xib; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2412,6 +2414,7 @@
E0A14D3B2372F0340044D131 /* GroupProfileViewController.swift */,
7B5E9B3F243700CD000AE24E /* ConversationCircleEditorViewController.swift */,
7CB2A57E27C386F0007D9DEE /* GroupsInCommonViewController.swift */,
948983B0284E66C00065DC5D /* ConversationCleaner.swift */,
);
path = Common;
sourceTree = "<group>";
Expand Down Expand Up @@ -4757,6 +4760,7 @@
7BC80A62221D1C07008586AD /* AssetTableHeaderView.swift in Sources */,
7B9553402243860C00CE95E6 /* PinValidationPresentationManager.swift in Sources */,
94046B93272DC28B007C1D4A /* GroupCallMembersManager.swift in Sources */,
948983B1284E66C00065DC5D /* ConversationCleaner.swift in Sources */,
7B4C6571242358D5003B78F9 /* LocationSearchNoResultView.swift in Sources */,
DF5D9F291F9C79E10036D5FD /* UIColorExtension.swift in Sources */,
DF0A0A5E24476EA000378B4F /* RefreshOffsetJob.swift in Sources */,
Expand Down
12 changes: 6 additions & 6 deletions Mixin/Service/Audio/Playlist/PlaylistManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ class PlaylistManager: NSObject {
object: nil)
notificationCenter.addObserver(self,
selector: #selector(messageWillDelete(_:)),
name: DeleteAttachmentMessageWork.willDeleteNotification,
name: DeleteMessageAttachmentWork.willDeleteNotification,
object: nil)
notificationCenter.addObserver(self,
selector: #selector(conversationDAOWillClearConversation(_:)),
name: ConversationDAO.willClearConversationNotification,
selector: #selector(conversationWillClean(_:)),
name: ConversationCleaner.willCleanNotification,
object: nil)
notificationCenter.addObserver(self,
selector: #selector(messageServiceWillRecallMessage(_:)),
Expand Down Expand Up @@ -774,7 +774,7 @@ extension PlaylistManager {
}

@objc private func messageWillDelete(_ notification: Notification) {
guard let messageId = notification.userInfo?[DeleteAttachmentMessageWork.messageIdUserInfoKey] as? String else {
guard let messageId = notification.userInfo?[DeleteMessageAttachmentWork.messageIdUserInfoKey] as? String else {
return
}
guard case .conversation = source else {
Expand All @@ -783,8 +783,8 @@ extension PlaylistManager {
removeItem(with: messageId)
}

@objc private func conversationDAOWillClearConversation(_ notification: Notification) {
guard let id = notification.userInfo?[ConversationDAO.conversationIdUserInfoKey] as? String else {
@objc private func conversationWillClean(_ notification: Notification) {
guard let id = notification.userInfo?[ConversationCleaner.conversationIdUserInfoKey] as? String else {
return
}
guard case let .conversation(conversationId) = source, conversationId == id else {
Expand Down
2 changes: 1 addition & 1 deletion Mixin/Service/Job/AttachmentUploadJob.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class AttachmentUploadJob: AttachmentLoadingJob {
return false
}
guard let fileUrl = fileUrl else {
let work = DeleteAttachmentMessageWork(message: message)
let work = DeleteMessageAttachmentWork(message: message)
WorkManager.general.addWork(work)
return false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,8 @@ class ConversationInputViewController: UIViewController {
self.deleteConversationButton.isBusy = false
}))
alert.addAction(UIAlertAction(title: R.string.localizable.delete_chat(), style: .destructive, handler: { (_) in
DispatchQueue.global().async { [weak self] in
ConversationDAO.shared.deleteChat(conversationId: conversationId)
DispatchQueue.main.async {
self?.navigationController?.backToHome()
}
ConversationCleaner.clean(conversationId: conversationId, intent: .delete) {
self.navigationController?.backToHome()
}
}))
present(alert, animated: true, completion: nil)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2707,13 +2707,11 @@ extension ConversationViewController {
guard let weakSelf = self, let indexPath = weakSelf.dataSource.indexPath(where: { $0.messageId == message.messageId }) else {
return
}
if DeleteAttachmentMessageWork.capableMessageCategories.contains(message.category) {
let work = DeleteAttachmentMessageWork(message: message)
WorkManager.general.addWork(work)
} else {
MessageDAO.shared.delete(id: message.messageId,
conversationId: message.conversationId,
deleteTranscriptChildren: true)
MessageDAO.shared.delete(id: message.messageId, conversationId: message.conversationId, deleteTranscriptChildren: false) { db in
if DeleteMessageAttachmentWork.capableMessageCategories.contains(message.category) {
let work = DeleteMessageAttachmentWork(message: message)
WorkManager.general.addPersistableWork(work, alongsideTransactionWith: db)
}
}
DispatchQueue.main.sync {
_ = weakSelf.dataSource?.removeViewModel(at: indexPath)
Expand Down
77 changes: 77 additions & 0 deletions Mixin/UserInterface/Controllers/Common/ConversationCleaner.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Foundation
import MixinServices
import GRDB

enum ConversationCleaner {

public static let willCleanNotification = Notification.Name("one.mixin.messenger.ConversationCleaner.willClean")
public static let conversationIdUserInfoKey = "cid"

enum Intent {
case delete
case clear
}

static func clean(conversationId: String, intent: Intent, completion: (() -> Void)? = nil) {
let hud = Hud()
hud.show(style: .busy, text: "", on: AppDelegate.current.mainWindow)
NotificationCenter.default.post(name: Self.willCleanNotification,
object: self,
userInfo: [Self.conversationIdUserInfoKey: conversationId])
DispatchQueue.global().async {
UserDatabase.current.write { db in
let categories = MessageCategory.allMediaCategoriesString.joined(separator: "', '")
let sql = "SELECT media_url, category FROM messages WHERE conversation_id = ? AND category IN ('\(categories)') AND media_url IS NOT NULL"
let attachments = try DeleteConversationAttachmentWork.Attachment.fetchAll(db, sql: sql, arguments: [conversationId])
let transcriptMessageIds = try MessageDAO.shared.getTranscriptMessageIds(conversationId: conversationId, database: db)
if !attachments.isEmpty || !transcriptMessageIds.isEmpty {
let work = DeleteConversationAttachmentWork(attachments: attachments, transcriptMessageIds: transcriptMessageIds)
WorkManager.general.addPersistableWork(work, alongsideTransactionWith: db)
}

try Message
.filter(Message.column(of: .conversationId) == conversationId)
.deleteAll(db)
try MessageMention
.filter(MessageMention.column(of: .conversationId) == conversationId)
.deleteAll(db)

switch intent {
case .delete:
try Conversation
.filter(Conversation.column(of: .conversationId) == conversationId)
.deleteAll(db)
try Participant
.filter(Participant.column(of: .conversationId) == conversationId)
.deleteAll(db)
try ParticipantSession
.filter(ParticipantSession.column(of: .conversationId) == conversationId)
.deleteAll(db)
case .clear:
try Conversation
.filter(Conversation.column(of: .conversationId) == conversationId)
.updateAll(db, [Conversation.column(of: .unseenMessageCount).set(to: 0)])
}

try ConversationDAO.shared.deleteFTSContent(with: conversationId, from: db)
try PinMessageDAO.shared.deleteAll(conversationId: conversationId, from: db)
db.afterNextTransactionCommit { (_) in
DispatchQueue.main.async {
switch intent {
case .delete:
NotificationCenter.default.post(name: conversationDidChangeNotification, object: nil)
hud.set(style: .notification, text: R.string.localizable.deleted())
case .clear:
let change = ConversationChange(conversationId: conversationId, action: .reload)
NotificationCenter.default.post(name: conversationDidChangeNotification, object: change)
hud.set(style: .notification, text: R.string.localizable.cleared())
}
hud.scheduleAutoHidden()
completion?()
}
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -207,21 +207,11 @@ extension GroupProfileViewController {
let conversationId = conversation.conversationId
let alert = UIAlertController(title: R.string.localizable.delete_group_chat_confirmation(conversation.name), message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: R.string.localizable.cancel(), style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: R.string.localizable.delete_chat(), style: .destructive, handler: { [weak self](_) in
let hud = Hud()
hud.show(style: .busy, text: "", on: AppDelegate.current.mainWindow)
DispatchQueue.global().async {
ConversationDAO.shared.deleteChat(conversationId: conversationId)
DispatchQueue.main.async {
guard let self = self else {
return
}
self.dismiss(animated: true) {
hud.set(style: .notification, text: R.string.localizable.done())
hud.scheduleAutoHidden()
if UIApplication.currentConversationId() == conversationId {
UIApplication.homeNavigationController?.backToHome()
}
alert.addAction(UIAlertAction(title: R.string.localizable.delete_chat(), style: .destructive, handler: { _ in
ConversationCleaner.clean(conversationId: conversationId, intent: .delete) {
self.dismiss(animated: true) {
if UIApplication.currentConversationId() == conversationId {
UIApplication.homeNavigationController?.backToHome()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,12 +250,7 @@ extension ProfileViewController {
alert.addAction(UIAlertAction(title: R.string.localizable.cancel(), style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: R.string.localizable.clear_chat(), style: .destructive, handler: { (_) in
self.dismiss(animated: true, completion: nil)
DispatchQueue.global().async {
ConversationDAO.shared.clearChat(conversationId: conversationId)
DispatchQueue.main.async {
showAutoHiddenHud(style: .notification, text: R.string.localizable.cleared())
}
}
ConversationCleaner.clean(conversationId: conversationId, intent: .clear)
}))
present(alert, animated: true, completion: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ class DatabaseUpgradeViewController: UIViewController {
AppGroupContainer.migrateIfNeeded()
TaskDatabase.reloadCurrent()
UserDatabase.reloadCurrent()
WorkDatabase.reloadCurrent()

if !AppGroupUserDefaults.Database.isSentSenderKeyCleared {
UserDatabase.current.clearSentSenderKey()
Expand Down
13 changes: 6 additions & 7 deletions Mixin/UserInterface/Controllers/Home/HomeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ class HomeViewController: UIViewController {
if AppGroupUserDefaults.User.hasRecoverMedia {
ConcurrentJobQueue.shared.addJob(job: RecoverMediaJob())
}
WorkManager.general.wakeUpPersistedWorks(with: [DeleteAttachmentMessageWork.self])
WorkManager.general.wakeUpPersistedWorks(with: [
DeleteMessageAttachmentWork.self,
DeleteConversationAttachmentWork.self
])
initializeFTSIfNeeded()
refreshExternalSchemesIfNeeded()
}
Expand Down Expand Up @@ -740,9 +743,7 @@ extension HomeViewController {
self.conversations.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
DispatchQueue.global().async {
ConversationDAO.shared.deleteChat(conversationId: conversationId)
}
ConversationCleaner.clean(conversationId: conversationId, intent: .delete)
}))
present(alert, animated: true, completion: nil)
}
Expand All @@ -764,9 +765,7 @@ extension HomeViewController {
self.conversations[indexPath.row].unseenMessageCount = 0
self.tableView.reloadRows(at: [indexPath], with: .automatic)
self.tableView.endUpdates()
DispatchQueue.global().async {
ConversationDAO.shared.clearChat(conversationId: conversationId)
}
ConversationCleaner.clean(conversationId: conversationId, intent: .clear)
}))
present(alert, animated: true, completion: nil)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ class LoginVerificationCodeViewController: VerificationCodeViewController {

TaskDatabase.reloadCurrent()
UserDatabase.reloadCurrent()
WorkDatabase.reloadCurrent()
if AppGroupUserDefaults.User.isLogoutByServer {
UserDatabase.current.clearSentSenderKey()
AppGroupUserDefaults.Database.isSentSenderKeyCleared = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ public final class ConversationDAO: UserDatabaseDAO {

public static let shared = ConversationDAO()

public static let willClearConversationNotification = Notification.Name("one.mixin.service.ConversationDAO.willClearConversation")
public static let conversationIdUserInfoKey = "cid"

private static let sqlQueryColumns = """
SELECT c.conversation_id as conversationId, c.owner_id as ownerId, c.icon_url as iconUrl,
c.announcement as announcement, c.category as category, c.name as name, c.status as status,
Expand Down Expand Up @@ -226,35 +223,6 @@ public final class ConversationDAO: UserDatabaseDAO {
}
}

public func clearChat(conversationId: String) {
let mediaUrls = MessageDAO.shared.getMediaUrls(conversationId: conversationId, categories: MessageCategory.allMediaCategories)
db.write { db in
let deletedTranscriptIds = try deleteTranscriptChildrenReferenced(by: conversationId, from: db)
NotificationCenter.default.post(onMainThread: Self.willClearConversationNotification,
object: self,
userInfo: [Self.conversationIdUserInfoKey: conversationId])
try Message
.filter(Message.column(of: .conversationId) == conversationId)
.deleteAll(db)
try MessageMention
.filter(MessageMention.column(of: .conversationId) == conversationId)
.deleteAll(db)
try Conversation
.filter(Conversation.column(of: .conversationId) == conversationId)
.updateAll(db, [Conversation.column(of: .unseenMessageCount).set(to: 0)])
try deleteFTSContent(with: conversationId, from: db)
try PinMessageDAO.shared.deleteAll(conversationId: conversationId, from: db)
db.afterNextTransactionCommit { (_) in
let job = AttachmentCleanUpJob(conversationId: conversationId,
mediaUrls: mediaUrls,
transcriptIds: deletedTranscriptIds)
ConcurrentJobQueue.shared.addJob(job: job)
let change = ConversationChange(conversationId: conversationId, action: .reload)
NotificationCenter.default.post(onMainThread: conversationDidChangeNotification, object: change)
}
}
}

public func getConversation(conversationId: String) -> ConversationItem? {
guard !conversationId.isEmpty else {
return nil
Expand Down Expand Up @@ -588,7 +556,7 @@ public final class ConversationDAO: UserDatabaseDAO {

extension ConversationDAO {

private func deleteFTSContent(with conversationId: String, from db: GRDB.Database) throws {
public func deleteFTSContent(with conversationId: String, from db: GRDB.Database) throws {
let sql = "DELETE FROM \(Message.ftsTableName) WHERE conversation_id MATCH ?"
try db.execute(sql: sql, arguments: [uuidTokenString(uuidString: conversationId)])
}
Expand Down
Loading

0 comments on commit 461edb1

Please sign in to comment.