diff --git a/Sources/ChatFeature/Controllers/MembersController.swift b/Sources/ChatFeature/Controllers/MembersController.swift index 488ad42517153bfa8fcb492dad11ced22ebf5a6e..c2a7ea2a0bef4319213c6b28641b06ee4e9a4e99 100644 --- a/Sources/ChatFeature/Controllers/MembersController.swift +++ b/Sources/ChatFeature/Controllers/MembersController.swift @@ -1,6 +1,7 @@ import UIKit import Models import Shared +import XXModels final class MembersController: UIViewController { lazy private var stackView = UIStackView() @@ -33,8 +34,8 @@ final class MembersController: UIViewController { for member in members { let memberView = MemberView() - memberView.titleLabel.text = member.username - memberView.avatarView.setupProfile(title: member.username, image: member.photo, size: .small) +// memberView.titleLabel.text = member.username +// memberView.avatarView.setupProfile(title: member.username, image: member.photo, size: .small) stackView.addArrangedSubview(memberView) } } diff --git a/Sources/ChatFeature/Controllers/SingleChatController.swift b/Sources/ChatFeature/Controllers/SingleChatController.swift index b6fd74a15936d7e89da27d03e555e5e16291af3e..b0f9324c2d84dc2d5aec7d589bd917c1e38f8275 100644 --- a/Sources/ChatFeature/Controllers/SingleChatController.swift +++ b/Sources/ChatFeature/Controllers/SingleChatController.swift @@ -1,5 +1,4 @@ import HUD -import DrawerFeature import UIKit import Theme import Models @@ -7,8 +6,10 @@ import Shared import Combine import XXLogger import QuickLook +import XXModels import Voxophone import ChatLayout +import DrawerFeature import DifferenceKit import ChatInputFeature import DependencyInjection diff --git a/Sources/ChatFeature/Coordinator/ChatCoordinator.swift b/Sources/ChatFeature/Coordinator/ChatCoordinator.swift index 3c04dc1ed0513f95e3fef74248df0fb5edac6185..64a8e46de2eada72bba4b371bed2b1d441a2b846 100644 --- a/Sources/ChatFeature/Coordinator/ChatCoordinator.swift +++ b/Sources/ChatFeature/Coordinator/ChatCoordinator.swift @@ -4,6 +4,7 @@ import Shared import QuickLook import Permissions import Presentation +import XXModels public protocol ChatCoordinating { func toCamera(from: UIViewController) diff --git a/Sources/ChatFeature/Helpers/BubbleBuilder.swift b/Sources/ChatFeature/Helpers/BubbleBuilder.swift index 3f9da31df8b01008102bb6bd066a5b27a69ea326..9deb4382350d104a3a7c6393aa32fb1599d8d217 100644 --- a/Sources/ChatFeature/Helpers/BubbleBuilder.swift +++ b/Sources/ChatFeature/Helpers/BubbleBuilder.swift @@ -9,20 +9,20 @@ final class Bubbler { audioBubble.dateLabel.text = item.date.asHoursAndMinutes() switch item.status { - case .received, .read: + case .received: audioBubble.lockerImageView.removeFromSuperview() audioBubble.backgroundColor = Asset.neutralWhite.color audioBubble.dateLabel.textColor = Asset.neutralDisabled.color audioBubble.progressLabel.textColor = Asset.neutralDisabled.color - case .receivingAttachment: + case .receiving: audioBubble.backgroundColor = Asset.neutralWhite.color audioBubble.dateLabel.textColor = Asset.neutralDisabled.color audioBubble.progressLabel.textColor = Asset.neutralDisabled.color - case .timedOut: + case .sendingTimedOut: audioBubble.backgroundColor = Asset.accentWarning.color audioBubble.dateLabel.textColor = Asset.neutralWhite.color audioBubble.progressLabel.textColor = Asset.neutralWhite.color - case .failedToSend: + case .sendingFailed: audioBubble.backgroundColor = Asset.accentDanger.color audioBubble.dateLabel.textColor = Asset.neutralWhite.color audioBubble.progressLabel.textColor = Asset.neutralWhite.color @@ -30,10 +30,12 @@ final class Bubbler { audioBubble.backgroundColor = Asset.brandBubble.color audioBubble.dateLabel.textColor = Asset.neutralWhite.color audioBubble.progressLabel.textColor = Asset.neutralWhite.color - case .sending, .sendingAttachment: + case .sending: audioBubble.backgroundColor = Asset.brandBubble.color audioBubble.dateLabel.textColor = Asset.neutralWhite.color audioBubble.progressLabel.textColor = Asset.neutralWhite.color + case .receivingFailed: + fatalError() } } @@ -46,20 +48,20 @@ final class Bubbler { imageBubble.dateLabel.text = item.date.asHoursAndMinutes() switch item.status { - case .received, .read: + case .received: imageBubble.lockerImageView.removeFromSuperview() imageBubble.backgroundColor = Asset.neutralWhite.color imageBubble.dateLabel.textColor = Asset.neutralDisabled.color imageBubble.progressLabel.textColor = Asset.neutralDisabled.color - case .receivingAttachment: + case .receiving: imageBubble.backgroundColor = Asset.neutralWhite.color imageBubble.dateLabel.textColor = Asset.neutralDisabled.color imageBubble.progressLabel.textColor = Asset.neutralDisabled.color - case .failedToSend: + case .sendingFailed: imageBubble.backgroundColor = Asset.accentDanger.color imageBubble.dateLabel.textColor = Asset.neutralWhite.color imageBubble.progressLabel.textColor = Asset.neutralWhite.color - case .timedOut: + case .sendingTimedOut: imageBubble.backgroundColor = Asset.accentWarning.color imageBubble.dateLabel.textColor = Asset.neutralWhite.color imageBubble.progressLabel.textColor = Asset.neutralWhite.color @@ -67,10 +69,12 @@ final class Bubbler { imageBubble.backgroundColor = Asset.brandBubble.color imageBubble.dateLabel.textColor = Asset.neutralWhite.color imageBubble.progressLabel.textColor = Asset.neutralWhite.color - case .sending, .sendingAttachment: + case .sending: imageBubble.backgroundColor = Asset.brandBubble.color imageBubble.dateLabel.textColor = Asset.neutralWhite.color imageBubble.progressLabel.textColor = Asset.neutralWhite.color + case .receivingFailed: + fatalError() } } @@ -85,19 +89,19 @@ final class Bubbler { let roundButtonColor: UIColor switch item.status { - case .received, .read, .receivingAttachment: + case .received, .receiving: bubble.lockerImageView.removeFromSuperview() bubble.backgroundColor = Asset.neutralWhite.color bubble.textView.textColor = Asset.neutralActive.color bubble.dateLabel.textColor = Asset.neutralDisabled.color roundButtonColor = Asset.neutralDisabled.color bubble.revertBottomStackOrder() - case .timedOut: + case .sendingTimedOut: bubble.backgroundColor = Asset.accentWarning.color bubble.textView.textColor = Asset.neutralWhite.color bubble.dateLabel.textColor = Asset.neutralWhite.color roundButtonColor = Asset.neutralWhite.color - case .failedToSend: + case .sendingFailed: bubble.backgroundColor = Asset.accentDanger.color bubble.textView.textColor = Asset.neutralWhite.color bubble.dateLabel.textColor = Asset.neutralWhite.color @@ -107,11 +111,13 @@ final class Bubbler { bubble.textView.textColor = Asset.neutralWhite.color bubble.dateLabel.textColor = Asset.neutralWhite.color roundButtonColor = Asset.neutralWhite.color - case .sending, .sendingAttachment: + case .sending: bubble.backgroundColor = Asset.brandBubble.color bubble.textView.textColor = Asset.neutralWhite.color bubble.dateLabel.textColor = Asset.neutralWhite.color roundButtonColor = Asset.neutralWhite.color + case .receivingFailed: + fatalError() } let attrString = NSAttributedString( @@ -187,7 +193,7 @@ final class Bubbler { let roundButtonColor: UIColor switch item.status { - case .received, .read, .receivingAttachment: + case .received, .receiving: bubble.senderLabel.removeFromSuperview() bubble.backgroundColor = Asset.neutralWhite.color bubble.textView.textColor = Asset.neutralActive.color @@ -196,7 +202,7 @@ final class Bubbler { bubble.replyView.container.backgroundColor = Asset.brandDefault.color bubble.replyView.space.backgroundColor = Asset.brandPrimary.color bubble.revertBottomStackOrder() - case .timedOut: + case .sendingTimedOut: bubble.senderLabel.removeFromSuperview() bubble.backgroundColor = Asset.accentWarning.color bubble.textView.textColor = Asset.neutralWhite.color @@ -204,7 +210,7 @@ final class Bubbler { roundButtonColor = Asset.neutralWhite.color bubble.replyView.space.backgroundColor = Asset.neutralWhite.color bubble.replyView.container.backgroundColor = Asset.brandLight.color - case .failedToSend: + case .sendingFailed: bubble.senderLabel.removeFromSuperview() bubble.backgroundColor = Asset.accentDanger.color bubble.textView.textColor = Asset.neutralWhite.color @@ -212,7 +218,7 @@ final class Bubbler { roundButtonColor = Asset.neutralWhite.color bubble.replyView.space.backgroundColor = Asset.neutralWhite.color bubble.replyView.container.backgroundColor = Asset.brandLight.color - case .sent, .sending, .sendingAttachment: + case .sent, .sending: bubble.senderLabel.removeFromSuperview() bubble.textView.textColor = Asset.neutralWhite.color bubble.backgroundColor = Asset.brandBubble.color @@ -220,6 +226,8 @@ final class Bubbler { roundButtonColor = Asset.neutralWhite.color bubble.replyView.space.backgroundColor = Asset.neutralWhite.color bubble.replyView.container.backgroundColor = Asset.brandLight.color + case .receivingFailed: + fatalError() } let attrString = NSAttributedString( diff --git a/Sources/ChatFeature/Helpers/CellConfigurator.swift b/Sources/ChatFeature/Helpers/CellConfigurator.swift index 5f2cb1b6b3348382304af392042bae3184010302..bebf5f357eb047827aae2e428ad63a3a4a5f2410 100644 --- a/Sources/ChatFeature/Helpers/CellConfigurator.swift +++ b/Sources/ChatFeature/Helpers/CellConfigurator.swift @@ -43,7 +43,7 @@ extension CellFactory { ) -> Self { .init( canBuild: { item in - (item.status == .received || item.status == .read || item.status == .receivingAttachment) + (item.status == .received || item.status == .receiving) && item.payload.reply == nil && item.payload.attachment != nil && item.payload.attachment?._extension == .audio @@ -65,7 +65,7 @@ extension CellFactory { ) cell.leftView.setup(with: model) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = {} Bubbler.build(audioBubble: cell.leftView, with: item) @@ -87,13 +87,13 @@ extension CellFactory { }.store(in: &cell.leftView.cancellables) cell.leftView.didTapRight = { - guard item.status != .receivingAttachment else { return } + guard item.status != .receiving else { return } voxophone.toggleLoudspeaker() } cell.leftView.didTapLeft = { - guard item.status != .receivingAttachment else { return } + guard item.status != .receiving else { return } if case .playing(url, _, _, _) = voxophone.state { voxophone.reset() @@ -114,9 +114,9 @@ extension CellFactory { .init( canBuild: { item in (item.status == .sent || - item.status == .failedToSend || - item.status == .sendingAttachment || - item.status == .timedOut) + item.status == .sending || + item.status == .sendingFailed || + item.status == .sendingTimedOut) && item.payload.reply == nil && item.payload.attachment != nil && item.payload.attachment?._extension == .audio @@ -137,7 +137,7 @@ extension CellFactory { ) cell.rightView.setup(with: model) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = {} Bubbler.build(audioBubble: cell.rightView, with: item) @@ -182,9 +182,9 @@ extension CellFactory { .init( canBuild: { item in (item.status == .sent || - item.status == .failedToSend || - item.status == .sendingAttachment || - item.status == .timedOut) + item.status == .sending || + item.status == .sendingFailed || + item.status == .sendingTimedOut) && item.payload.reply == nil && item.payload.attachment != nil && item.payload.attachment?._extension == .image @@ -196,7 +196,7 @@ extension CellFactory { Bubbler.build(imageBubble: cell.rightView, with: item) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = {} if let image = UIImage(data: attachment.data!) { @@ -211,7 +211,7 @@ extension CellFactory { static func incomingImage() -> Self { .init( canBuild: { item in - (item.status == .received || item.status == .read || item.status == .receivingAttachment) + (item.status == .received || item.status == .receiving) && item.payload.reply == nil && item.payload.attachment != nil && item.payload.attachment?._extension == .image @@ -222,7 +222,7 @@ extension CellFactory { let cell: IncomingImageCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) Bubbler.build(imageBubble: cell.leftView, with: item) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = {} cell.leftView.imageView.image = UIImage(data: attachment.data!) return cell @@ -256,7 +256,7 @@ extension CellFactory { ) ) - cell.canReply = item.status.canReply + cell.canReply = item.status == .sent cell.performReply = performReply cell.rightView.didTapShowRound = { showRound(item.roundURL) } return cell @@ -272,7 +272,7 @@ extension CellFactory { ) -> Self { .init( canBuild: { item in - (item.status == .received || item.status == .read) + item.status == .received && item.payload.reply != nil && item.payload.attachment == nil @@ -287,7 +287,7 @@ extension CellFactory { sender: name(item.payload.reply!.senderId) ) ) - cell.canReply = item.status.canReply + cell.canReply = item.status == .received cell.performReply = performReply cell.leftView.didTapShowRound = { showRound(item.roundURL) } cell.leftView.revertBottomStackOrder() @@ -303,7 +303,7 @@ extension CellFactory { ) -> Self { .init( canBuild: { item in - (item.status == .failedToSend || item.status == .timedOut) + (item.status == .sendingFailed || item.status == .sendingTimedOut) && item.payload.reply != nil && item.payload.attachment == nil @@ -319,7 +319,7 @@ extension CellFactory { ) ) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = performReply return cell } @@ -334,7 +334,7 @@ extension CellFactory { ) -> Self { .init( canBuild: { item in - (item.status == .received || item.status == .read) + item.status == .received && item.payload.reply == nil && item.payload.attachment == nil @@ -342,7 +342,7 @@ extension CellFactory { let cell: IncomingTextCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) Bubbler.build(bubble: cell.leftView, with: item) - cell.canReply = item.status.canReply + cell.canReply = item.status == .received cell.performReply = performReply cell.leftView.didTapShowRound = { showRound(item.roundURL) } cell.leftView.revertBottomStackOrder() @@ -365,7 +365,7 @@ extension CellFactory { let cell: OutgoingTextCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) Bubbler.build(bubble: cell.rightView, with: item) - cell.canReply = item.status.canReply + cell.canReply = item.status == .sent cell.performReply = performReply cell.rightView.didTapShowRound = { showRound(item.roundURL) } @@ -377,7 +377,7 @@ extension CellFactory { static func outgoingFailedText(performReply: @escaping () -> Void) -> Self { .init( canBuild: { item in - (item.status == .failedToSend || item.status == .timedOut) + (item.status == .sendingFailed || item.status == .sendingTimedOut) && item.payload.reply == nil && item.payload.attachment == nil @@ -385,7 +385,7 @@ extension CellFactory { let cell: OutgoingFailedTextCell = collectionView.dequeueReusableCell(forIndexPath: indexPath) Bubbler.build(bubble: cell.rightView, with: item) - cell.canReply = item.status.canReply + cell.canReply = false cell.performReply = performReply return cell } @@ -425,9 +425,9 @@ struct ActionFactory { switch action { case .reply: - guard item.status == .read || item.status == .received || item.status == .sent else { return nil } + guard item.status == .received || item.status == .sent else { return nil } case .retry: - guard item.status == .failedToSend || item.status == .timedOut else { return nil } + guard item.status == .sendingFailed || item.status == .sendingTimedOut else { return nil } case .delete, .copy: break } diff --git a/Sources/ChatFeature/Models/ChatItem.swift b/Sources/ChatFeature/Models/ChatItem.swift index 9e68dcf4c13386cd04d390d2530007db6c8cdb5c..22d728d5272ae2eb066a4dc6d8a829d276d113bc 100644 --- a/Sources/ChatFeature/Models/ChatItem.swift +++ b/Sources/ChatFeature/Models/ChatItem.swift @@ -1,4 +1,5 @@ import Models +import XXModels import Foundation import DifferenceKit diff --git a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift index d1be4b6ee2b69fb786f1d371162c4f4d8c420f1c..152472cd4723f240e87b95076aa15ea7c346f0b6 100644 --- a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift +++ b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift @@ -4,6 +4,7 @@ import Models import Shared import Combine import XXLogger +import XXModels import Foundation import Integration import Permissions diff --git a/Sources/Integration/Session/SessionType.swift b/Sources/Integration/Session/SessionType.swift index b77fe940575a3b177c73b0410bc50f24555400c9..19b020dbcca50e9e9bb43a64d46faf02cc569064 100644 --- a/Sources/Integration/Session/SessionType.swift +++ b/Sources/Integration/Session/SessionType.swift @@ -10,6 +10,8 @@ public protocol SessionType { var hasRunningTasks: Bool { get } var isOnline: AnyPublisher<Bool, Never> { get } + var dbManager: Database { get } + func deleteMyself() throws func getId(from: Data) -> Data? diff --git a/Sources/LaunchFeature/LaunchCoordinator.swift b/Sources/LaunchFeature/LaunchCoordinator.swift index 2f446810a29e5639190477705ffd8225bb88eb37..59f6c5f2f5ed421f2109c6226d154d8e85c1a190 100644 --- a/Sources/LaunchFeature/LaunchCoordinator.swift +++ b/Sources/LaunchFeature/LaunchCoordinator.swift @@ -1,5 +1,6 @@ import UIKit import Models +import XXModels import Presentation public protocol LaunchCoordinating { diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift index 5e1b78a61a04e567242a2b058f7d5afa872bfb7f..0eb26949bdbcb0d3b9382dc1f53b90726faf4ae9 100644 --- a/Sources/LaunchFeature/LaunchViewModel.swift +++ b/Sources/LaunchFeature/LaunchViewModel.swift @@ -1,8 +1,10 @@ import HUD import Shared import Models + import Combine import Defaults +import XXModels import Foundation import Integration import Permissions @@ -118,21 +120,23 @@ final class LaunchViewModel { } func getContactWith(userId: Data) -> Contact? { - guard let session = try? DependencyInjection.Container.shared.resolve() as SessionType, - let contact = session.getContactWith(userId: userId) else { - return nil - } - - return contact + fatalError() +// guard let session = try? DependencyInjection.Container.shared.resolve() as SessionType, +// let contact = session.getContactWith(userId: userId) else { +// return nil +// } +// +// return contact } func getGroupInfoWith(groupId: Data) -> GroupChatInfo? { - guard let session: SessionType = try? DependencyInjection.Container.shared.resolve(), - let info = session.getGroupChatInfoWith(groupId: groupId) else { - return nil - } - - return info + fatalError() +// guard let session: SessionType = try? DependencyInjection.Container.shared.resolve(), +// let info = session.getGroupChatInfoWith(groupId: groupId) else { +// return nil +// } +// +// return info } private func versionFailed(error: Error) { diff --git a/Sources/MenuFeature/ViewModels/MenuViewModel.swift b/Sources/MenuFeature/ViewModels/MenuViewModel.swift index 92eb785136c7cc4ba6ff6fb30fc597d93d6a3ac7..3c70e6aa106a3a31f3ae0dac6d469711a90b7dc8 100644 --- a/Sources/MenuFeature/ViewModels/MenuViewModel.swift +++ b/Sources/MenuFeature/ViewModels/MenuViewModel.swift @@ -1,4 +1,5 @@ import Combine +import XXModels import Defaults import Foundation import Integration @@ -11,24 +12,21 @@ final class MenuViewModel { @KeyObject(.username, defaultValue: "") var username: String var requestCount: AnyPublisher<Int, Never> { - Publishers.CombineLatest( - session.contacts(.received), - session.groups(.pending) - ).map { (contacts, groups) in - let contactRequests = contacts.filter { - $0.status == .verified || - $0.status == .confirming || - $0.status == .confirmationFailed || - $0.status == .verificationFailed || - $0.status == .verificationInProgress - } - - let groupRequests = groups.filter { - $0.status == .pending - } - - return contactRequests.count + groupRequests.count - }.eraseToAnyPublisher() + let groupQuery = Group.Query(authStatus: [.pending]) + let contactsQuery = Contact.Query(authStatus: [ + .verified, + .confirming, + .confirmationFailed, + .verificationFailed, + .verificationInProgress + ]) + + return Publishers.CombineLatest( + session.dbManager.fetchContactsPublisher(contactsQuery).catch { _ in Just([]) }, + session.dbManager.fetchGroupsPublisher(groupQuery).catch { _ in Just([]) } + ) + .map { $0.0.count + $0.1.count } + .eraseToAnyPublisher() } var xxdk: String {