Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MailCore/Models/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public final class Message: Object, Decodable, ObjectKeyIdentifiable {
}

public var formattedSubject: String {
return subject ?? MailResourcesStrings.Localizable.noSubjectTitle
return SubjectFormatter.cleanNotNullOrEmptySubject.format(subject)
}

public var displayDate: DisplayDate {
Expand Down
6 changes: 1 addition & 5 deletions MailCore/Models/Thread.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import Foundation
import InfomaniakDI
import MailResources
import OrderedCollections
import RealmSwift

Expand Down Expand Up @@ -125,10 +124,7 @@ public class Thread: Object, Decodable, Identifiable {
}

public var formattedSubject: String {
guard let subject, !subject.isEmpty else {
return MailResourcesStrings.Localizable.noSubjectTitle
}
return subject
return SubjectFormatter.cleanNotNullOrEmptySubject.format(subject)
}

public var shouldPresentAsDraft: Bool {
Expand Down
1 change: 1 addition & 0 deletions MailCore/Utils/NotificationsHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ public enum NotificationsHelper {
guard let liveMessage = realm.object(ofType: Message.self, forPrimaryKey: message.uid) else {
return
}

liveMessage.preview = String(preview.prefix(512))
}
}
Expand Down
78 changes: 78 additions & 0 deletions MailCore/Utils/SubjectFormatter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Infomaniak Mail - iOS App
Copyright (C) 2025 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import Foundation
import MailResources

public struct SubjectFormatter: FormatStyle {
private func clean(_ value: String) -> String {
let normalizedSubject = value.precomposedStringWithCompatibilityMapping

let cleanedSubject = String(normalizedSubject.unicodeScalars.map { scalar -> Character in
if scalar.isIllegalInSubject {
return " "
} else {
return Character(scalar)
}
})

return cleanedSubject
}

private func cleanNotNullOrEmpty(_ value: String?) -> String {
guard let value, !value.isEmpty else {
return MailResourcesStrings.Localizable.noSubjectTitle
}

return clean(value)
}

public func format(_ value: String?) -> String {
return cleanNotNullOrEmpty(value)
}
}

public extension FormatStyle where Self == SubjectFormatter {
static var cleanNotNullOrEmptySubject: SubjectFormatter {
return SubjectFormatter()
}
}

extension UnicodeScalar {
var isInvisible: Bool {
properties.generalCategory == .format ||
properties.generalCategory == .control
}

var isBidiControl: Bool {
switch value {
case 0x202A ... 0x202E, 0x2066 ... 0x2069:
return true
default:
return false
}
}

var isIllegalInSubject: Bool {
if isInvisible || properties.isJoinControl || isBidiControl {
return true
}

return false
}
}
Loading