diff --git a/Ring/Ring/Constants/Generated/Strings.swift b/Ring/Ring/Constants/Generated/Strings.swift index b1cd370f9ba6b89747bec6360467fb44c6b46bb7..f362a886d07595efa6c6bfbab40a728f0103169c 100644 --- a/Ring/Ring/Constants/Generated/Strings.swift +++ b/Ring/Ring/Constants/Generated/Strings.swift @@ -41,8 +41,8 @@ internal enum L10n { internal static let enableAccount = L10n.tr("Localizable", "account.enableAccount", fallback: "Enable Account") /// Me internal static let me = L10n.tr("Localizable", "account.me", fallback: "Me") - /// account need to be migrated - internal static let needMigration = L10n.tr("Localizable", "account.needMigration", fallback: "account need to be migrated") + /// Account requires migration. + internal static let needMigration = L10n.tr("Localizable", "account.needMigration", fallback: "Account requires migration.") /// Port internal static let port = L10n.tr("Localizable", "account.port", fallback: "Port") /// Enter Port Number @@ -105,8 +105,6 @@ internal enum L10n { internal static let contactMeOnJamiTitle = L10n.tr("Localizable", "accountPage.contactMeOnJamiTitle", fallback: "Contact me on Jami!") /// Encrypt account internal static let createPassword = L10n.tr("Localizable", "accountPage.createPassword", fallback: "Encrypt account") - /// Account Details - internal static let credentialsHeader = L10n.tr("Localizable", "accountPage.credentialsHeader", fallback: "Account Details") /// Enter current password internal static let currentPasswordPlaceholder = L10n.tr("Localizable", "accountPage.currentPasswordPlaceholder", fallback: "Enter current password") /// Device revocation error @@ -267,8 +265,6 @@ internal enum L10n { internal static let upnpEnabled = L10n.tr("Localizable", "accountPage.upnpEnabled", fallback: "Use UPnP") /// Use proxy list internal static let useProxyList = L10n.tr("Localizable", "accountPage.useProxyList", fallback: "Use proxy list") - /// username: not registered - internal static let usernameNotRegistered = L10n.tr("Localizable", "accountPage.usernameNotRegistered", fallback: "username: not registered") /// Enter desired username internal static let usernamePlaceholder = L10n.tr("Localizable", "accountPage.usernamePlaceholder", fallback: "Enter desired username") /// Register @@ -289,10 +285,6 @@ internal enum L10n { internal static let doneAction = L10n.tr("Localizable", "actions.doneAction", fallback: "Done") /// Go to Settings internal static let goToSettings = L10n.tr("Localizable", "actions.goToSettings", fallback: "Go to Settings") - /// Audio Call - internal static let startAudioCall = L10n.tr("Localizable", "actions.startAudioCall", fallback: " Audio Call") - /// Video Call - internal static let startVideoCall = L10n.tr("Localizable", "actions.startVideoCall", fallback: " Video Call") /// Stop sharing internal static let stopLocationSharing = L10n.tr("Localizable", "actions.stopLocationSharing", fallback: "Stop sharing") } @@ -329,10 +321,6 @@ internal enum L10n { internal static let dbFailedTitle = L10n.tr("Localizable", "alerts.dbFailedTitle", fallback: "An error happened when launching Jami") /// An error occurred while connecting to Jami Account Management Server (JAMS). Please try again. If the problem persists, contact your system administrator. internal static let errorWrongCredentials = L10n.tr("Localizable", "alerts.errorWrongCredentials", fallback: "An error occurred while connecting to Jami Account Management Server (JAMS). Please try again. If the problem persists, contact your system administrator.") - /// Incoming call from - internal static let incomingCallAllertTitle = L10n.tr("Localizable", "alerts.incomingCallAllertTitle", fallback: "Incoming call from ") - /// Ignore - internal static let incomingCallButtonIgnore = L10n.tr("Localizable", "alerts.incomingCallButtonIgnore", fallback: "Ignore") /// Turn on “Location Services” to allow “Jami” to determine device location. internal static let locationServiceIsDisabled = L10n.tr("Localizable", "alerts.locationServiceIsDisabled", fallback: "Turn on “Location Services” to allow “Jami” to determine device location.") /// Share my location @@ -405,8 +393,6 @@ internal enum L10n { internal static let connecting = L10n.tr("Localizable", "calls.connecting", fallback: "Connecting…") /// Call with internal static let currentCallWith = L10n.tr("Localizable", "calls.currentCallWith", fallback: "Call with ") - /// wants to talk to you - internal static let incomingCallInfo = L10n.tr("Localizable", "calls.incomingCallInfo", fallback: "wants to talk to you") /// Lower hand internal static let lowerHand = L10n.tr("Localizable", "calls.lowerHand", fallback: "Lower hand") /// Maximize @@ -441,16 +427,14 @@ internal enum L10n { internal static let addToContactsLabel = L10n.tr("Localizable", "conversation.addToContactsLabel", fallback: "Add to contacts?") /// Contact blocked internal static let contactBlocked = L10n.tr("Localizable", "conversation.contactBlocked", fallback: "Contact blocked") - /// deleted a message - internal static let deletedMessage = L10n.tr("Localizable", "conversation.deletedMessage", fallback: "deleted a message") + /// %@ deleted a message + internal static func deletedMessage(_ p1: Any) -> String { + return L10n.tr("Localizable", "conversation.deletedMessage", String(describing: p1), fallback: "%@ deleted a message") + } /// Edited internal static let edited = L10n.tr("Localizable", "conversation.edited", fallback: "Edited") /// An error occurred while saving the image to the gallery. internal static let errorSavingImage = L10n.tr("Localizable", "conversation.errorSavingImage", fallback: "An error occurred while saving the image to the gallery.") - /// You are currently receiving a live location from - internal static let explanationReceivingLocationFrom = L10n.tr("Localizable", "conversation.explanationReceivingLocationFrom", fallback: "You are currently receiving a live location from ") - /// You are currently sharing your location with - internal static let explanationSendingLocationTo = L10n.tr("Localizable", "conversation.explanationSendingLocationTo", fallback: "You are currently sharing your location with ") /// sent you a conversation invitation. internal static let incomingRequest = L10n.tr("Localizable", "conversation.incomingRequest", fallback: "sent you a conversation invitation.") /// In reply to @@ -463,8 +447,10 @@ internal enum L10n { internal static func receivedRequest(_ p1: Any) -> String { return L10n.tr("Localizable", "conversation.receivedRequest", String(describing: p1), fallback: "%@ sent you a conversation invitation.") } - /// replied to - internal static let repliedTo = L10n.tr("Localizable", "conversation.repliedTo", fallback: "replied to") + /// %@ replied to %@ + internal static func repliedTo(_ p1: Any, _ p2: Any) -> String { + return L10n.tr("Localizable", "conversation.repliedTo", String(describing: p1), String(describing: p2), fallback: "%@ replied to %@") + } /// Hello, /// Do you want to join the conversation? internal static let requestMessage = L10n.tr("Localizable", "conversation.requestMessage", fallback: "Hello,\nDo you want to join the conversation?") @@ -498,10 +484,8 @@ internal enum L10n { internal static let encryptTitle = L10n.tr("Localizable", "createAccount.encryptTitle", fallback: "Encrypt account with password") /// Invalid username. Please enter a valid username. internal static let invalidUsername = L10n.tr("Localizable", "createAccount.invalidUsername", fallback: "Invalid username. Please enter a valid username.") - /// Loading… - internal static let loading = L10n.tr("Localizable", "createAccount.loading", fallback: "Loading…") - /// looking for availability… - internal static let lookingForUsernameAvailability = L10n.tr("Localizable", "createAccount.lookingForUsernameAvailability", fallback: "looking for availability…") + /// Looking for availability… + internal static let lookingForUsernameAvailability = L10n.tr("Localizable", "createAccount.lookingForUsernameAvailability", fallback: "Looking for availability…") /// You can choose a username to help others more easily find and reach you on Jami. internal static let nameExplanation = L10n.tr("Localizable", "createAccount.nameExplanation", fallback: "You can choose a username to help others more easily find and reach you on Jami.") /// New account @@ -512,16 +496,14 @@ internal enum L10n { internal static let timeoutMessage = L10n.tr("Localizable", "createAccount.timeoutMessage", fallback: "Username registration is in progress. Please wait…") /// Account Created internal static let timeoutTitle = L10n.tr("Localizable", "createAccount.timeoutTitle", fallback: "Account Created") - /// username already taken - internal static let usernameAlreadyTaken = L10n.tr("Localizable", "createAccount.usernameAlreadyTaken", fallback: "username already taken") + /// Username already taken + internal static let usernameAlreadyTaken = L10n.tr("Localizable", "createAccount.usernameAlreadyTaken", fallback: "Username already taken") /// Account was created but username was not registered internal static let usernameNotRegisteredMessage = L10n.tr("Localizable", "createAccount.UsernameNotRegisteredMessage", fallback: "Account was created but username was not registered") /// Network error internal static let usernameNotRegisteredTitle = L10n.tr("Localizable", "createAccount.UsernameNotRegisteredTitle", fallback: "Network error") /// The username is available. internal static let usernameValid = L10n.tr("Localizable", "createAccount.usernameValid", fallback: "The username is available.") - /// Adding account - internal static let waitCreateAccountTitle = L10n.tr("Localizable", "createAccount.waitCreateAccountTitle", fallback: "Adding account") } internal enum CreateProfile { /// Create profile picture @@ -592,22 +574,36 @@ internal enum L10n { internal enum GeneratedMessage { /// Invitation received internal static let contactAdded = L10n.tr("Localizable", "generatedMessage.contactAdded", fallback: "Invitation received") - /// was blocked from the conversation. - internal static let contactBlocked = L10n.tr("Localizable", "generatedMessage.contactBlocked", fallback: "was blocked from the conversation.") - /// has left the conversation. - internal static let contactLeftConversation = L10n.tr("Localizable", "generatedMessage.contactLeftConversation", fallback: "has left the conversation.") - /// was unblocked from the conversation. - internal static let contactUnblocked = L10n.tr("Localizable", "generatedMessage.contactUnblocked", fallback: "was unblocked from the conversation.") - /// has joined the conversation. - internal static let invitationAccepted = L10n.tr("Localizable", "generatedMessage.invitationAccepted", fallback: "has joined the conversation.") - /// was invited to join the conversation. - internal static let invitationReceived = L10n.tr("Localizable", "generatedMessage.invitationReceived", fallback: "was invited to join the conversation.") + /// %@ was blocked from the conversation. + internal static func contactBlocked(_ p1: Any) -> String { + return L10n.tr("Localizable", "generatedMessage.contactBlocked", String(describing: p1), fallback: "%@ was blocked from the conversation.") + } + /// %@ has left the conversation. + internal static func contactLeftConversation(_ p1: Any) -> String { + return L10n.tr("Localizable", "generatedMessage.contactLeftConversation", String(describing: p1), fallback: "%@ has left the conversation.") + } + /// %@ was unblocked from the conversation. + internal static func contactUnblocked(_ p1: Any) -> String { + return L10n.tr("Localizable", "generatedMessage.contactUnblocked", String(describing: p1), fallback: "%@ was unblocked from the conversation.") + } + /// %@ has joined the conversation. + internal static func invitationAccepted(_ p1: Any) -> String { + return L10n.tr("Localizable", "generatedMessage.invitationAccepted", String(describing: p1), fallback: "%@ has joined the conversation.") + } + /// %@ was invited to join the conversation. + internal static func invitationReceived(_ p1: Any) -> String { + return L10n.tr("Localizable", "generatedMessage.invitationReceived", String(describing: p1), fallback: "%@ was invited to join the conversation.") + } /// Live location sharing internal static let liveLocationSharing = L10n.tr("Localizable", "generatedMessage.liveLocationSharing", fallback: "Live location sharing") /// Missed incoming call internal static let missedIncomingCall = L10n.tr("Localizable", "generatedMessage.missedIncomingCall", fallback: "Missed incoming call") /// Missed outgoing call internal static let missedOutgoingCall = L10n.tr("Localizable", "generatedMessage.missedOutgoingCall", fallback: "Missed outgoing call") + /// Your invitation was accepted. + internal static let nonSwarmInvitationAccepted = L10n.tr("Localizable", "generatedMessage.nonSwarmInvitationAccepted", fallback: "Your invitation was accepted.") + /// You sent an invitation. + internal static let nonSwarmInvitationReceived = L10n.tr("Localizable", "generatedMessage.nonSwarmInvitationReceived", fallback: "You sent an invitation.") /// Outgoing call internal static let outgoingCall = L10n.tr("Localizable", "generatedMessage.outgoingCall", fallback: "Outgoing call") /// Conversation created @@ -724,18 +720,16 @@ internal enum L10n { internal static let title = L10n.tr("Localizable", "importFromArchive.title", fallback: "Import from archive") } internal enum Invitations { - /// accepted - internal static let accepted = L10n.tr("Localizable", "invitations.accepted", fallback: "accepted") - /// blocked - internal static let blocked = L10n.tr("Localizable", "invitations.blocked", fallback: "blocked") - /// declined - internal static let declined = L10n.tr("Localizable", "invitations.declined", fallback: "declined") + /// Accepted + internal static let accepted = L10n.tr("Localizable", "invitations.accepted", fallback: "Accepted") + /// Blocked + internal static let blocked = L10n.tr("Localizable", "invitations.blocked", fallback: "Blocked") + /// Declined + internal static let declined = L10n.tr("Localizable", "invitations.declined", fallback: "Declined") /// Invitations received internal static let list = L10n.tr("Localizable", "invitations.list", fallback: "Invitations received") /// No invitations internal static let noInvitations = L10n.tr("Localizable", "invitations.noInvitations", fallback: "No invitations") - /// pending - internal static let pending = L10n.tr("Localizable", "invitations.pending", fallback: "pending") } internal enum LinkDevice { /// An error occurred while exporting the account. diff --git a/Ring/Ring/Database/DBManager.swift b/Ring/Ring/Database/DBManager.swift index ad89e6766d29d2482751944ddd5065b07438c69f..d40243aee5259d033dd7639c14af3bc355a44e8d 100644 --- a/Ring/Ring/Database/DBManager.swift +++ b/Ring/Ring/Database/DBManager.swift @@ -49,9 +49,9 @@ enum GeneratedMessage: Int { case .contactAdded: return L10n.GeneratedMessage.contactAdded case .invitationReceived: - return L10n.GeneratedMessage.invitationReceived + return L10n.GeneratedMessage.nonSwarmInvitationReceived case .invitationAccepted: - return L10n.GeneratedMessage.invitationAccepted + return L10n.GeneratedMessage.nonSwarmInvitationAccepted case .missedOutgoingCall: return L10n.GeneratedMessage.missedOutgoingCall case .missedIncomingCall: @@ -156,7 +156,7 @@ enum InteractionType: String { case .call: return .call case .contact: - return .contact + return .contact( .add) case .iTransfer: return .fileTransfer case .oTransfer: diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContactMessageVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContactMessageVM.swift index 72d44f208b428b6bd8cceaa5e95d37114c88d926..434c5742aee5314c2013055c324de3b57e8ebebe 100644 --- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContactMessageVM.swift +++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/ContactMessageVM.swift @@ -43,7 +43,9 @@ class ContactMessageVM: ObservableObject, MessageAppearanceProtocol, AvatarImage var message: MessageModel var username = "" { didSet { - self.content = self.username.isEmpty ? self.message.content : self.username + " " + self.message.content + let jamiId = message.uri.isEmpty ? message.authorId : message.uri + let name = self.username.isEmpty ? jamiId : self.username + self.content = self.message.getContactInteractionString(name: name) ?? "" } } var infoState: PublishSubject<State>? @@ -64,7 +66,7 @@ class ContactMessageVM: ObservableObject, MessageAppearanceProtocol, AvatarImage func setInfoState(state: PublishSubject<State>) { self.infoState = state - if message.type == .contact && message.incoming { + if message.type.isContact && message.incoming { let jamiId = message.uri.isEmpty ? message.authorId : message.uri requestAvatar(jamiId: jamiId) requestName(jamiId: jamiId) diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift index 904681582bdcd99883003e62fd6b14423053efb4..b809a89f8a87a7a77f42067910990a0b50828605 100644 --- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift +++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageContentVM.swift @@ -123,7 +123,7 @@ class MessageContentVM: ObservableObject, PreviewViewControllerDelegate, PlayerD @Published var finalImage: UIImage? @Published var messageDeleted = false @Published var messageEdited = false - @Published var messageDeletedText = " " + L10n.Conversation.deletedMessage + @Published var messageDeletedText = "" @Published var editIndicator = L10n.Conversation.edited @Published var editionColor = Color.secondary @Published var scale: CGFloat = 1 @@ -173,7 +173,7 @@ class MessageContentVM: ObservableObject, PreviewViewControllerDelegate, PlayerD didSet { DispatchQueue.main.async { [weak self] in guard let self = self else { return } - self.messageDeletedText = self.username + " " + L10n.Conversation.deletedMessage + self.messageDeletedText = L10n.Conversation.deletedMessage(self.username) } } } @@ -222,7 +222,7 @@ class MessageContentVM: ObservableObject, PreviewViewControllerDelegate, PlayerD if self.isLink() { let backgroundIsLightColor: Bool = self.backgroundColor.isLight(threshold: 0.8) ?? true self.styling.textColor = backgroundIsLightColor ? .blue : .white - } else if !self.isIncoming && self.type != .contact { + } else if !self.isIncoming && !self.type.isContact { self.styling.textColor = Color.white } else { self.styling.textColor = self.styling.defaultTextColor @@ -238,7 +238,7 @@ class MessageContentVM: ObservableObject, PreviewViewControllerDelegate, PlayerD } private func updateBackgroundColor() { - if self.type == .contact || self.content.containsOnlyEmoji && !self.messageDeleted && !self.messageEdited { + if self.type.isContact || self.content.containsOnlyEmoji && !self.messageDeleted && !self.messageEdited { self.backgroundColor = .clear } else { self.backgroundColor = isIncoming ? Color(.jamiMsgCellReceived) : Color(preferencesColor) diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageReplyTargetVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageReplyTargetVM.swift index a3284bdf65a0a4c898be48f6b89d5b5a2d2d65f7..7bf0e15776029d420e17dce4bc2d8175eb03075a 100644 --- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageReplyTargetVM.swift +++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageReplyTargetVM.swift @@ -97,8 +97,8 @@ class MessageReplyTargetVM: ObservableObject, MessageAppearanceProtocol, AvatarI private func getInReplyMessage() -> String { let inReplyToSelf = L10n.Conversation.inReplyTo + " \(L10n.Account.me)" let inReplyToOther = L10n.Conversation.inReplyTo + " \(targetReplyUsername)" - let repliedByOtherToSelf = "\(username) " + L10n.Conversation.repliedTo + " \(L10n.Account.me)" - let repliedByOtherToOther = "\(username) " + L10n.Conversation.repliedTo + " \(targetReplyUsername)" + let repliedByOtherToSelf = L10n.Conversation.repliedTo(username, L10n.Account.me) + let repliedByOtherToOther = L10n.Conversation.repliedTo(username, targetReplyUsername) switch (replyIsIncoming(), targetReplyIsIncoming()) { case (true, true): diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift index 17f0e3f72e9619e25f90ab248f634e6933f1baa6..dfa68791d4a382edba92fb5f2662e3ffc6021e9d 100644 --- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift +++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessageRowVM.swift @@ -78,7 +78,7 @@ class MessageRowVM: ObservableObject, MessageAppearanceProtocol, MessageReadObse init(message: MessageModel) { self.message = message self.incoming = message.incoming - self.centeredMessage = message.type == .contact || message.type == .initial + self.centeredMessage = message.type.isContact || message.type == .initial self.readBorderColor = Color(UIColor.systemBackground) self.timeString = getTimeLabelString() self.updateMessageStatus() diff --git a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift index 6c61e9963105d2b22124d89776cecb5782d710e2..cf88288291782c6efe6b76ebe2c88d582f5fb17f 100644 --- a/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift +++ b/Ring/Ring/Features/Conversations/Conversation/MessageSwiftUI/ViewModels/MessagesListVM.swift @@ -584,7 +584,7 @@ class MessagesListVM: ObservableObject { let lastMessage = lastMessageContainer.message self.lastMessageDate.accept(lastMessage.receivedDate.conversationTimestamp()) - if lastMessage.type != .contact { + if !lastMessage.type.isContact { self.lastMessage.accept(lastMessage.content) } else { // For contact messages, update when the display name is available. @@ -925,7 +925,7 @@ class MessagesListVM: ObservableObject { private func isBreakingSequence(message: MessageModel, secondMessage: MessageModel) -> Bool { let differentUri = message.uri != secondMessage.uri - let messageTypeCheck = message.type == .contact || message.type == .initial + let messageTypeCheck = message.type.isContact || message.type == .initial let differentAuthor = message.authorId != secondMessage.authorId let isReplyCheck = message.isReply() || secondMessage.isReply() let hasReactions = !message.reactions.isEmpty || !secondMessage.reactions.isEmpty diff --git a/Ring/Ring/Models/MessageModel.swift b/Ring/Ring/Models/MessageModel.swift index 69d611f6e570817c1e84a8c8ad9350b54a095d8a..950e6025573d9a316a2d4363b37b860497d44388 100644 --- a/Ring/Ring/Models/MessageModel.swift +++ b/Ring/Ring/Models/MessageModel.swift @@ -37,14 +37,66 @@ enum MessageAttributes: String { case totalSize = "totalSize" } -enum MessageType: String { - case text = "text/plain" - case fileTransfer = "application/data-transfer+json" - case contact = "member" - case call = "application/call-history+json" - case merge = "merge" - case initial = "initial" - case profile = "application/update-profile" +enum MessageType: Equatable { + case text + case fileTransfer + case contact(ContactAction) + case call + case merge + case initial + case profile + + var rawValue: String { + switch self { + case .text: return "text/plain" + case .fileTransfer: return "application/data-transfer+json" + case .contact: return "member" + case .call: return "application/call-history+json" + case .merge: return "merge" + case .initial: return "initial" + case .profile: return "application/update-profile" + } + } + + init?(rawValue: String) { + switch rawValue { + case "text/plain": self = .text + case "application/data-transfer+json": self = .fileTransfer + case "member": self = .contact(.add) + case "application/call-history+json": self = .call + case "merge": self = .merge + case "initial": self = .initial + case "application/update-profile": self = .profile + default: return nil + } + } + + static func == (lhs: MessageType, rhs: MessageType) -> Bool { + switch (lhs, rhs) { + case (.text, .text), + (.fileTransfer, .fileTransfer), + (.call, .call), + (.merge, .merge), + (.initial, .initial), + (.contact, .contact), + (.profile, .profile): + return true + default: + return false + } + } + + var isContact: Bool { + if case .contact = self { return true } + return false + } + + func getInteractionString(name: String, isIncoming: Bool) -> String? { + if case .contact(let action) = self { + return action.getInteractionString(name: name, isIncomig: isIncoming) + } + return nil + } } enum ContactAction: String { @@ -53,6 +105,22 @@ enum ContactAction: String { case join case banned case unban + + func getInteractionString(name: String, isIncomig: Bool) -> String { + switch self { + case .add: + return isIncomig ? L10n.GeneratedMessage.invitationReceived(name) : + L10n.GeneratedMessage.contactAdded + case .join: + return isIncomig ? L10n.GeneratedMessage.invitationAccepted(name) : L10n.GeneratedMessage.youJoined + case .remove: + return L10n.GeneratedMessage.contactLeftConversation(name) + case.banned: + return L10n.GeneratedMessage.contactBlocked(name) + case .unban: + return L10n.GeneratedMessage.contactUnblocked(name) + } + } } class MessageAction: Identifiable, Equatable, Hashable { @@ -161,7 +229,7 @@ public class MessageModel { let messageType = MessageType(rawValue: type) { self.type = messageType } - if let content = info[MessageAttributes.body.rawValue], self.type == .text { + if let content = info[MessageAttributes.body.rawValue], self.type == MessageType.text { self.content = content } if let reply = info[MessageAttributes.reply.rawValue] { @@ -209,19 +277,7 @@ public class MessageModel { case .contact: if let action = info[MessageAttributes.action.rawValue], let contactAction = ContactAction(rawValue: action) { - switch contactAction { - case .add: - self.content = self.incoming ? L10n.GeneratedMessage.invitationReceived : - L10n.GeneratedMessage.contactAdded - case .join: - self.content = self.incoming ? L10n.GeneratedMessage.invitationAccepted : L10n.GeneratedMessage.youJoined - case .remove: - self.content = L10n.GeneratedMessage.contactLeftConversation - case.banned: - self.content = L10n.GeneratedMessage.contactBlocked - case .unban: - self.content = L10n.GeneratedMessage.contactUnblocked - } + self.type = .contact(contactAction) } case .fileTransfer: if let fileid = info[MessageAttributes.fileId.rawValue] { @@ -238,6 +294,10 @@ public class MessageModel { } } + func getContactInteractionString(name: String) -> String? { + return self.type.getInteractionString(name: name, isIncoming: incoming) + } + func updateFrom(info: [String: String]) { if let content = info[MessageAttributes.body.rawValue], self.type == .text { self.content = content diff --git a/Ring/Ring/Resources/en.lproj/Localizable.strings b/Ring/Ring/Resources/en.lproj/Localizable.strings index d6f852ef906a4f88656562785fa78c227d68288f..a45673362a0a32990e9430ef695e4a52f507458d 100644 --- a/Ring/Ring/Resources/en.lproj/Localizable.strings +++ b/Ring/Ring/Resources/en.lproj/Localizable.strings @@ -129,8 +129,6 @@ "conversation.addToContactsLabel" = "Add to contacts?"; "conversation.notContactLabel" = "is not in your contact list"; "conversation.messagePlaceholder" = "Write to"; -"conversation.explanationSendingLocationTo" = "You are currently sharing your location with "; -"conversation.explanationReceivingLocationFrom" = "You are currently receiving a live location from "; "conversation.errorSavingImage" = "An error occurred while saving the image to the gallery."; "conversation.receivedRequest" = "%@ sent you a conversation invitation."; "conversation.incomingRequest" = "sent you a conversation invitation."; @@ -140,18 +138,17 @@ "conversation.synchronizationTitle" = "You have accepted the conversation invitation."; "conversation.synchronizationMessage" = "Waiting for %@ to connect to synchronize the conversation…"; "conversation.inReplyTo" = "In reply to"; -"conversation.repliedTo" = "replied to"; +"conversation.repliedTo" = "%@ replied to %@"; "conversation.yourself" = "You"; "conversation.edited" = "Edited"; -"conversation.deletedMessage" = "deleted a message"; +"conversation.deletedMessage" = "%@ deleted a message"; "conversation.contactBlocked" = "Contact blocked"; // Invitations "invitations.noInvitations" = "No invitations"; -"invitations.pending" = "pending"; -"invitations.accepted" = "accepted"; -"invitations.declined" = "declined"; -"invitations.blocked" = "blocked"; +"invitations.accepted" = "Accepted"; +"invitations.declined" = "Declined"; +"invitations.blocked" = "Blocked"; "invitations.list" = "Invitations received"; // Walkthrough @@ -176,12 +173,10 @@ // Create Account form "createAccount.createAccountFormTitle" = "Join Jami"; -"createAccount.lookingForUsernameAvailability" = "looking for availability…"; +"createAccount.lookingForUsernameAvailability" = "Looking for availability…"; "createAccount.invalidUsername" = "Invalid username. Please enter a valid username."; -"createAccount.usernameAlreadyTaken" = "username already taken"; +"createAccount.usernameAlreadyTaken" = "Username already taken"; "createAccount.usernameValid" = "The username is available."; -"createAccount.loading" = "Loading…"; -"createAccount.waitCreateAccountTitle" = "Adding account"; "createAccount.UsernameNotRegisteredTitle" = "Network error"; "createAccount.UsernameNotRegisteredMessage" = "Account was created but username was not registered"; "createAccount.timeoutTitle" = "Account Created"; @@ -261,15 +256,10 @@ "actions.deleteAction" = "Delete"; "actions.backAction" = "Back"; "actions.doneAction" = "Done"; -"alerts.incomingCallAllertTitle" = "Incoming call from "; -"alerts.incomingCallButtonIgnore" = "Ignore"; -"actions.startAudioCall" = " Audio Call"; -"actions.startVideoCall" = " Video Call"; "actions.goToSettings" = "Go to Settings"; "actions.stopLocationSharing" = "Stop sharing"; // Calls -"calls.incomingCallInfo" = "wants to talk to you"; "calls.ringing" = "Ringing…"; "calls.connecting" = "Connecting…"; "calls.callFinished" = "Call finished"; @@ -286,8 +276,6 @@ "accountPage.devicesListHeader" = "Devices"; "accountPage.settingsHeader" = "Settings"; "accountPage.notificationsHeader" = "Notifications"; -"accountPage.usernameNotRegistered" = "username: not registered"; -"accountPage.credentialsHeader" = "Account Details"; "accountPage.blockedContacts" = "Blocked contacts"; "accountPage.unblockContact" = "Unblock"; "accountPage.proxyAddressAlert" = "Provide proxy address"; @@ -420,7 +408,7 @@ "account.statusConnecting" = "Connecting"; "account.statusUnknown" = "Unknown"; "account.statusConnectionerror" = "Connection Error"; -"account.needMigration" = "account need to be migrated"; +"account.needMigration" = "Account requires migration."; "account.me" = "Me"; // Block List Page @@ -464,16 +452,18 @@ // Generated Message "generatedMessage.contactAdded" = "Invitation received"; "generatedMessage.swarmCreated" = "Conversation created"; -"generatedMessage.invitationReceived" = "was invited to join the conversation."; -"generatedMessage.invitationAccepted" = "has joined the conversation."; +"generatedMessage.invitationReceived" = "%@ was invited to join the conversation."; +"generatedMessage.invitationAccepted" = "%@ has joined the conversation."; "generatedMessage.youJoined" = "You joined the conversation."; -"generatedMessage.contactBlocked" = "was blocked from the conversation."; -"generatedMessage.contactUnblocked" = "was unblocked from the conversation."; +"generatedMessage.contactBlocked" = "%@ was blocked from the conversation."; +"generatedMessage.contactUnblocked" = "%@ was unblocked from the conversation."; "generatedMessage.outgoingCall" = "Outgoing call"; "generatedMessage.missedOutgoingCall" = "Missed outgoing call"; "generatedMessage.missedIncomingCall" = "Missed incoming call"; "generatedMessage.liveLocationSharing" = "Live location sharing"; -"generatedMessage.contactLeftConversation" = "has left the conversation."; +"generatedMessage.contactLeftConversation" = "%@ has left the conversation."; +"generatedMessage.nonSwarmInvitationReceived" = "You sent an invitation."; +"generatedMessage.nonSwarmInvitationAccepted" = "Your invitation was accepted."; // General Settings "generalSettings.videoSettings" = "Video settings"; diff --git a/Ring/Ring/Services/ConversationsService.swift b/Ring/Ring/Services/ConversationsService.swift index 514b60568ede5972a826867ce3b661969216990a..be6aed489a7759b435957ccd4d319e73163494c5 100644 --- a/Ring/Ring/Services/ConversationsService.swift +++ b/Ring/Ring/Services/ConversationsService.swift @@ -99,7 +99,7 @@ class ConversationsService { } /// filter out contact requests let conversationsFromDB = conversationsModels.filter { conversation in - !(conversation.messages.count == 1 && conversation.messages.first!.content == L10n.GeneratedMessage.invitationReceived) + !(conversation.messages.count == 1 && conversation.messages.first!.content == L10n.GeneratedMessage.nonSwarmInvitationReceived) } /// Filter out conversations that already added to swarm .filter { conversation in @@ -487,7 +487,7 @@ class ConversationsService { conversation.accountId == toAccountId }) .first { - let content = (message.type == .contact || message.type == .call) ? + let content = (message.type.isContact || message.type == .call) ? GeneratedMessage.init(from: message.content).toMessage(with: Int(duration)) : message.content message.content = content @@ -750,7 +750,7 @@ class ConversationsService { conversation.accountId == accountId }) .first { - let content = (message.type == .contact || message.type == .call) ? + let content = (message.type.isContact || message.type == .call) ? GeneratedMessage.init(from: message.content).toMessage(with: Int(0)) : message.content message.content = content diff --git a/Ring/Ring/Services/GeneratedInteractionsManager.swift b/Ring/Ring/Services/GeneratedInteractionsManager.swift index 131a81336fb86a68d0818cd9c92a44972574e21d..76454df41e209540351fe21fffc971dcae6d8532 100644 --- a/Ring/Ring/Services/GeneratedInteractionsManager.swift +++ b/Ring/Ring/Services/GeneratedInteractionsManager.swift @@ -103,7 +103,7 @@ class GeneratedInteractionsManager { return } // remove conversation if it contain only contact messages - let messages = conversation.messages.filter({ $0.type != .contact }) + let messages = conversation.messages.filter({ !$0.type.isContact }) if !messages.isEmpty { return