WIP: check for any untouched strings

pull/1023/head
Ryan ZHAO 1 year ago
parent 4054796da1
commit fd1c368ca0

@ -27,7 +27,7 @@ extension ProjectState {
"_SharedTestUtilities/", // Exclude shared test directory
"external/" // External dependencies
]
static let excludedPhrases: Set<String> = [ "", " ", ",", ", ", "null" ]
static let excludedPhrases: Set<String> = [ "", " ", " ", ",", ", ", "null", "\"", "@[0-9a-fA-F]{66}", "^[0-9A-Fa-f]+$" ]
static let excludedUnlocalisedStringLineMatching: Set<MatchType> = [
.contains(ProjectState.lintSuppression, caseSensitive: false),
.prefix("#import", caseSensitive: false),
@ -46,9 +46,9 @@ extension ProjectState {
.contains("[UIImage imageNamed:", caseSensitive: false),
.contains("UIFont(name:", caseSensitive: false),
.contains(".dateFormat =", caseSensitive: false),
.contains(".accessibilityLabel =", caseSensitive: false),
.contains(".accessibilityValue =", caseSensitive: false),
.contains(".accessibilityIdentifier =", caseSensitive: false),
.contains("accessibilityLabel =", caseSensitive: false),
.contains("accessibilityValue =", caseSensitive: false),
.contains("accessibilityIdentifier =", caseSensitive: false),
.contains("accessibilityIdentifier:", caseSensitive: false),
.contains("accessibilityLabel:", caseSensitive: false),
.contains("Accessibility(identifier:", caseSensitive: false),
@ -73,6 +73,17 @@ extension ProjectState {
.previousLine(numEarlier: 2, .contains("Accessibility(", caseSensitive: false))
),
.contains("SQL(", caseSensitive: false),
.contains(" == ", caseSensitive: false),
.contains("forResource:", caseSensitive: false),
.contains("imageName:", caseSensitive: false),
.contains(".userInfo[", caseSensitive: false),
.contains("payload[", caseSensitive: false),
.contains(".infoDictionary?[", caseSensitive: false),
.contains("accessibilityId:", caseSensitive: false),
.contains("key:", caseSensitive: false),
.contains("separator:", caseSensitive: false),
.nextLine(.contains(".put(key:", caseSensitive: false)),
.nextLine(.contains(".localized()", caseSensitive: false)),
.regex(".*static var databaseTableName: String"),
.regex("Logger\\..*\\("),
.regex("OWSLogger\\..*\\("),
@ -545,6 +556,7 @@ indirect enum MatchType: Hashable {
case containsAnd(String, caseSensitive: Bool, MatchType)
case regex(String)
case previousLine(numEarlier: Int, MatchType)
case nextLine(MatchType)
func matches(_ value: String, _ index: Int, _ lines: [String]) -> Bool {
switch self {
@ -578,6 +590,10 @@ indirect enum MatchType: Hashable {
let targetIndex: Int = (index - numEarlier)
return type.matches(lines[targetIndex], targetIndex, lines)
case .nextLine(let type):
guard index + 1 < lines.count else { return false }
return type.matches(lines[index + 1], index + 1, lines)
}
}
}

@ -182,7 +182,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
func reportIncomingCallIfNeeded(completion: @escaping (Error?) -> Void) {
guard case .answer = mode else {
SessionCallManager.reportFakeCall(info: "Call not in answer mode")
SessionCallManager.reportFakeCall(info: "Call not in answer mode") // stringlint:disable
return
}

@ -43,7 +43,7 @@ public final class SessionCallManager: NSObject, CallManagerProtocol {
}
static func buildProviderConfiguration(useSystemCallLog: Bool) -> CXProviderConfiguration {
let providerConfiguration = CXProviderConfiguration(localizedName: "Session")
let providerConfiguration = CXProviderConfiguration(localizedName: "Session") // stringlint:disable
providerConfiguration.supportsVideo = true
providerConfiguration.maximumCallGroups = 1
providerConfiguration.maximumCallsPerCallGroup = 1

@ -629,7 +629,7 @@ final class CallVC: UIViewController, VideoPreviewDelegate {
}
@objc private func updateDuration() {
callDurationLabel.text = String(format: "%.2d:%.2d", duration/60, duration%60)
callDurationLabel.text = String(format: "%.2d:%.2d", duration/60, duration%60) // stringlint:disable
duration += 1
}

@ -74,7 +74,7 @@ class VideoPreviewVC: UIViewController, CameraManagerDelegate {
private lazy var titleLabel: UILabel = {
let result = UILabel()
result.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
result.text = "Preview"
result.text = "preview".localized()
result.themeTextColor = .textPrimary
result.textAlignment = .center

@ -730,7 +730,7 @@ extension ConversationVC:
let newText: String = snInputView.text.replacingCharacters(
in: currentMentionStartIndex...,
with: "@\(mentionInfo.profile.displayName(for: self.viewModel.threadData.threadVariant)) "
with: "@\(mentionInfo.profile.displayName(for: self.viewModel.threadData.threadVariant)) " // stringlint:disable
)
snInputView.text = newText
@ -789,8 +789,8 @@ extension ConversationVC:
func replaceMentions(in text: String) -> String {
var result = text
for mention in mentions {
guard let range = result.range(of: "@\(mention.profile.displayName(for: mention.threadVariant))") else { continue }
result = result.replacingCharacters(in: range, with: "@\(mention.profile.id)")
guard let range = result.range(of: "@\(mention.profile.displayName(for: mention.threadVariant))") else { continue } // stringlint:disable
result = result.replacingCharacters(in: range, with: "@\(mention.profile.id)") // stringlint:disable
}
return result
@ -1702,14 +1702,14 @@ extension ConversationVC:
))
// HACK: Extracting this info from the error string is pretty dodgy
let prefix: String = "HTTP request failed at destination (Service node "
let prefix: String = "HTTP request failed at destination (Service node " // stringlint:disable
if let mostRecentFailureText: String = cellViewModel.mostRecentFailureText, mostRecentFailureText.hasPrefix(prefix) {
let rest = mostRecentFailureText.substring(from: prefix.count)
if let index = rest.firstIndex(of: ")") {
if let index = rest.firstIndex(of: ")") { // stringlint:disable
let snodeAddress = String(rest[rest.startIndex..<index])
sheet.addAction(UIAlertAction(title: "Copy Service Node Info", style: .default) { _ in
sheet.addAction(UIAlertAction(title: "Copy Service Node Info", style: .default) { _ in // stringlint:disable
UIPasteboard.general.string = snodeAddress
})
}
@ -1721,11 +1721,13 @@ extension ConversationVC:
func joinOpenGroup(name: String?, url: String) {
// Open groups can be unsafe, so always ask the user whether they want to join one
let finalName: String = (name ?? "Open Group")
let message: String = "Are you sure you want to join the \(finalName) open group?";
let finalName: String = (name ?? "Community")
let message: String = "communityJoinDescription"
.put(key: "communityname", value: finalName)
.localized()
let modal: ConfirmationModal = ConfirmationModal(
info: ConfirmationModal.Info(
title: "Join \(finalName)?",
title: "join".localized() + " \(finalName)?",
body: .attributedText(
NSMutableAttributedString(string: message)
.adding(
@ -1975,7 +1977,6 @@ extension ConversationVC:
case .standardOutgoing, .standardIncoming: break
}
let threadName: String = self.viewModel.threadData.displayName
let userPublicKey: String = getUserHexEncodedPublicKey()
// Remote deletion logic
@ -2419,7 +2420,7 @@ extension ConversationVC:
// Create URL
let directory: String = Singleton.appContext.temporaryDirectory
let fileName: String = "\(SnodeAPI.currentOffsetTimestampMs()).m4a"
let fileName: String = "\(SnodeAPI.currentOffsetTimestampMs()).m4a" // stringlint:disable
let url: URL = URL(fileURLWithPath: directory).appendingPathComponent(fileName)
// Set up audio session

@ -104,7 +104,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
return result
}()
lazy var recordVoiceMessageActivity = AudioActivity(audioDescription: "Voice message", behavior: .playAndRecord)
lazy var recordVoiceMessageActivity = AudioActivity(audioDescription: "Voice message", behavior: .playAndRecord) // stringlint:disable
lazy var searchController: ConversationSearchController = {
let result: ConversationSearchController = ConversationSearchController(
@ -1807,7 +1807,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
func updateUnreadCountView(unreadCount: UInt?) {
let unreadCount: Int = Int(unreadCount ?? 0)
let fontSize: CGFloat = (unreadCount < 10000 ? Values.verySmallFontSize : 8)
unreadCountLabel.text = (unreadCount < 10000 ? "\(unreadCount)" : "9999+")
unreadCountLabel.text = (unreadCount < 10000 ? "\(unreadCount)" : "9999+") // stringlint:disable
unreadCountLabel.font = .boldSystemFont(ofSize: fontSize)
unreadCountView.isHidden = (unreadCount == 0)
}

@ -68,7 +68,7 @@ public class ConversationViewModel: OWSAudioPlayerDelegate {
return "blockBlockedDescription".localized()
default: return "Thread is blocked. Unblock it?" // Should not happen
default: return "Thread is blocked. Unblock it?" // Should not happen // stringlint:disable
}
}()

@ -297,7 +297,7 @@ extension EmojiPickerCollectionView: UICollectionViewDelegateFlowLayout {
}
private class EmojiCell: UICollectionViewCell {
static let reuseIdentifier = "EmojiCell"
static let reuseIdentifier = "EmojiCell" // stringlint:disable
let emojiLabel = UILabel()
@ -327,7 +327,7 @@ private class EmojiCell: UICollectionViewCell {
}
private class EmojiSectionHeader: UICollectionReusableView {
static let reuseIdentifier = "EmojiSectionHeader"
static let reuseIdentifier = "EmojiSectionHeader" // stringlint:disable
let label = UILabel()

@ -122,7 +122,7 @@ final class VoiceMessageRecordingView: UIView {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.themeTextColor = .textPrimary
result.text = "0:00"
result.text = "0:00" // stringlint:disable
return result
}()

@ -54,7 +54,7 @@ class DisappearingMessageTimerView: UIView {
}
private func updateIcon() {
let imageName: String = "disappearing_message_\(String(format: "%02d", 5 * self.progress))"
let imageName: String = "disappearing_message_\(String(format: "%02d", 5 * self.progress))" // stringlint:disable
self.iconImageView.image = UIImage(named: imageName)?.withRenderingMode(.alwaysTemplate)
}

@ -34,13 +34,13 @@ final class MediaPlaceholderView: UIView {
cellViewModel.variant == .standardIncoming,
let attachment: Attachment = cellViewModel.attachments?.first
else {
return ("actionsheet_document_black", "file") // Should never occur
return ("actionsheet_document_black", "file".localized().lowercased()) // Should never occur
}
if attachment.isAudio { return ("attachment_audio", "audio") }
if attachment.isImage || attachment.isVideo { return ("actionsheet_camera_roll_black", "media") }
if attachment.isAudio { return ("attachment_audio", "audio".localized().lowercased()) }
if attachment.isImage || attachment.isVideo { return ("actionsheet_camera_roll_black", "media".localized().lowercased()) }
return ("actionsheet_document_black", "file")
return ("actionsheet_document_black", "file".localized().lowercased())
}()
// Image view
@ -62,7 +62,9 @@ final class MediaPlaceholderView: UIView {
// Body label
let titleLabel = UILabel()
titleLabel.font = .systemFont(ofSize: Values.mediumFontSize)
titleLabel.text = "Tap to download \(attachmentDescription)"
titleLabel.text = "attachmentsTapToDownload"
.put(key: "filetype", value: attachmentDescription)
.localized()
titleLabel.themeTextColor = textColor
titleLabel.lineBreakMode = .byTruncatingTail

@ -48,7 +48,7 @@ final class OpenGroupInvitationView: UIView {
let urlLabel = UILabel()
urlLabel.font = .systemFont(ofSize: Values.verySmallFontSize)
urlLabel.text = {
if let range = rawUrl.range(of: "?public_key=") {
if let range = rawUrl.range(of: "?public_key=") { // stringlint:disable
return String(rawUrl[..<range.lowerBound])
}
@ -64,7 +64,7 @@ final class OpenGroupInvitationView: UIView {
// Icon
let iconSize = OpenGroupInvitationView.iconSize
let iconName = (isOutgoing ? "Globe" : "Plus")
let iconName = (isOutgoing ? "Globe" : "Plus") // stringlint:disable
let iconImageViewSize = OpenGroupInvitationView.iconImageViewSize
let iconImageView = UIImageView(
image: UIImage(named: iconName)?

@ -122,7 +122,7 @@ final class QuoteView: UIView {
if let attachment: Attachment = attachment {
let isAudio: Bool = MIMETypeUtil.isAudio(attachment.contentType)
let fallbackImageName: String = (isAudio ? "attachment_audio" : "actionsheet_document_black")
let fallbackImageName: String = (isAudio ? "attachment_audio" : "actionsheet_document_black") // stringlint:disable
let imageView: UIImageView = UIImageView(
image: UIImage(named: fallbackImageName)?
.resizedImage(to: CGSize(width: iconSize, height: iconSize))?

@ -88,7 +88,7 @@ final class ReactionButton: UIView {
emojiLabel.text = viewModel.emoji.rawValue
numberLabel.text = (viewModel.number < 1000 ?
"\(viewModel.number)" :
String(format: "%.1f", Float(viewModel.number) / 1000) + "k"
String(format: "%.1f", Float(viewModel.number) / 1000) + "k" // stringlint:disable
)
numberLabel.isHidden = (!showNumber && viewModel.number <= 1)

@ -200,8 +200,8 @@ import SessionUtilitiesKit
let groupAnimation = CAAnimationGroup()
groupAnimation.animations = [
makeAnimation("fillColor", colorValues),
makeAnimation("path", pathValues)
makeAnimation("fillColor", colorValues), // stringlint:disable
makeAnimation("path", pathValues) // stringlint:disable
]
groupAnimation.duration = animationDuration
groupAnimation.repeatCount = MAXFLOAT

@ -77,7 +77,7 @@ public final class VoiceMessageView: UIView {
private lazy var countdownLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.text = "0:00"
result.text = "0:00" // stringlint:disable
result.themeTextColor = .textPrimary
return result
@ -86,7 +86,7 @@ public final class VoiceMessageView: UIView {
private lazy var speedUpLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.text = "1.5x"
result.text = "1.5x" // stringlint:disable
result.themeTextColor = .textPrimary
result.textAlignment = .center
result.alpha = 0

@ -1199,7 +1199,7 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
SessionThreadViewModel.searchTermParts(searchText)
.map { part -> String in
guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part }
guard part.hasPrefix("\"") && part.hasSuffix("\"") else { return part } // stringlint:disable
let partRange = (part.index(after: part.startIndex)..<part.index(before: part.endIndex))
return String(part[partRange])
@ -1211,8 +1211,8 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
normalizedBody
.ranges(
of: (Singleton.hasAppContext && Singleton.appContext.isRTL ?
"(\(part.lowercased()))(^|[^a-zA-Z0-9])" :
"(^|[^a-zA-Z0-9])(\(part.lowercased()))"
"(\(part.lowercased()))(^|[^a-zA-Z0-9])" : // stringlint:disable
"(^|[^a-zA-Z0-9])(\(part.lowercased()))" // stringlint:disable
),
options: [.regularExpression]
)

@ -551,7 +551,7 @@ extension ReactionListSheet {
emojiLabel.text = emoji
numberLabel.text = (count < 1000 ?
"\(count)" :
String(format: "%.1fk", Float(count) / 1000)
String(format: "%.1fk", Float(count) / 1000) // stringlint:disable
)
snContentView.themeBorderColor = (isCurrentSelection ? .primary : .clear)
}

@ -1,3 +1,5 @@
// stringlint:disable
import Foundation
import SignalCoreKit
import SessionUtilitiesKit

@ -136,7 +136,7 @@ class GlobalSearchViewController: BaseVC, SessionUtilRespondingViewController, U
// See more https://developer.apple.com/documentation/uikit/uisearchbar/1624283-showscancelbutton?language=objc
if UIDevice.current.isIPad {
let ipadCancelButton = UIButton()
ipadCancelButton.setTitle("Cancel", for: .normal)
ipadCancelButton.setTitle("cancel".localized(), for: .normal)
ipadCancelButton.setThemeTitleColor(.textPrimary, for: .normal)
ipadCancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside)
searchBarContainer.addSubview(ipadCancelButton)

@ -49,7 +49,7 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
private lazy var seedReminderView: SeedReminderView = {
let result = SeedReminderView(hasContinueButton: true)
result.accessibilityLabel = "Recovery phrase reminder"
let title = "You're almost finished! 80%"
let title = "You're almost finished! 80%" // stringlint:disable
result.subtitle = "view_seed_reminder_subtitle_1".localized()
result.setProgress(0.8, animated: false)
result.delegate = self
@ -60,7 +60,7 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "80%")
range: (title as NSString).range(of: "80%") // stringlint:disable
)
result?.title = attributedTitle
}

@ -5,7 +5,7 @@ import SessionUIKit
import SignalUtilitiesKit
class MessageRequestsCell: UITableViewCell {
static let reuseIdentifier = "MessageRequestsCell"
static let reuseIdentifier = "MessageRequestsCell" // stringlint:disable
// MARK: - Initialization

@ -23,8 +23,8 @@ public class NewConversationViewModel {
let initialCharacter: String = (displayName.length > 0 ? displayName.substring(to: 1) : "")
let section: String = initialCharacter.capitalized.isSingleAlphabet ?
initialCharacter.capitalized :
"#"
initialCharacter.capitalized :
"#" // stringlint:disable
if groupedContacts[section] == nil {
groupedContacts[section] = SectionData(

@ -37,7 +37,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
var hasSelectedCell: Bool = false
var imageInfos = [GiphyImageInfo]()
private let kCellReuseIdentifier = "kCellReuseIdentifier"
private let kCellReuseIdentifier = "kCellReuseIdentifier" // stringlint:disable
var progressiveSearchTimer: Timer?

@ -8,5 +8,5 @@ public class GiphyDownloader: ProxiedContentDownloader {
// MARK: - Properties
public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs")
public static let giphyDownloader = GiphyDownloader(downloadFolderName: "GIFs") // stringlint:disable
}

@ -72,7 +72,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
// quickly toggle between the Capture and the Picker VC's, we use the same custom "X"
// icon here rather than the system "stop" icon so that the spacing matches exactly.
// Otherwise there's a noticable shift in the icon placement.
let cancelImage = UIImage(imageLiteralResourceName: "X")
let cancelImage = #imageLiteral(resourceName: "X")
let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel))
cancelButton.themeTintColor = .textPrimary

@ -759,7 +759,7 @@ private class MediaTileViewLayout: UICollectionViewFlowLayout {
private class MediaGallerySectionHeader: UICollectionReusableView {
static let reuseIdentifier = "MediaGallerySectionHeader"
static let reuseIdentifier = "MediaGallerySectionHeader" // stringlint:disable
// HACK: scrollbar incorrectly appears *behind* section headers
// in collection view on iOS11 =(
@ -817,7 +817,7 @@ private class MediaGallerySectionHeader: UICollectionReusableView {
private class MediaGalleryStaticHeader: UICollectionViewCell {
static let reuseIdentifier = "MediaGalleryStaticHeader"
static let reuseIdentifier = "MediaGalleryStaticHeader" // stringlint:disable
let label = UILabel()

@ -341,11 +341,11 @@ class PhotoCaptureViewController: OWSViewController {
let imageName: String
switch photoCapture.flashMode {
case .auto:
imageName = "ic_flash_mode_auto"
imageName = "ic_flash_mode_auto" // stringlint:disable
case .on:
imageName = "ic_flash_mode_on"
imageName = "ic_flash_mode_on" // stringlint:disable
case .off:
imageName = "ic_flash_mode_off"
imageName = "ic_flash_mode_off" // stringlint:disable
default: preconditionFailure()
}
@ -646,7 +646,7 @@ class RecordingTimerView: UIView {
private lazy var timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "mm:ss"
formatter.timeZone = TimeZone(identifier: "UTC")!
formatter.timeZone = TimeZone(identifier: "UTC")! // stringlint:disable
return formatter
}()

@ -186,7 +186,7 @@ class PhotoCollectionContents {
exportSession.outputFileType = AVFileType.mp4
exportSession.metadataItemFilter = AVMetadataItemFilter.forSharing()
let exportPath = OWSFileSystem.temporaryFilePath(withFileExtension: "mp4")
let exportPath = OWSFileSystem.temporaryFilePath(withFileExtension: "mp4") // stringlint:disable
let exportURL = URL(fileURLWithPath: exportPath)
exportSession.outputURL = exportURL

@ -862,9 +862,9 @@ private enum LifecycleMethod: Equatable {
var timingName: String {
switch self {
case .finishLaunching: return "Launch"
case .enterForeground: return "EnterForeground"
case .didBecomeActive: return "BecomeActive"
case .finishLaunching: return "Launch" // stringlint:disable
case .enterForeground: return "EnterForeground" // stringlint:disable
case .didBecomeActive: return "BecomeActive" // stringlint:disable
}
}
@ -888,11 +888,11 @@ private enum StartupError: Error {
var name: String {
switch self {
case .databaseError(StorageError.startupFailed), .databaseError(DatabaseError.SQLITE_LOCKED):
return "Database startup failed"
return "Database startup failed" // stringlint:disable
case .failedToRestore: return "Failed to restore"
case .databaseError: return "Database error"
case .startupTimeout: return "Startup timeout"
case .failedToRestore: return "Failed to restore" // stringlint:disable
case .databaseError: return "Database error" // stringlint:disable
case .startupTimeout: return "Startup timeout" // stringlint:disable
}
}

@ -165,7 +165,7 @@ final class MainAppContext: AppContext {
func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjects: [Any]) {
if UIApplication.shared.isIdleTimerDisabled != shouldBeBlocking {
if shouldBeBlocking {
var logString: String = "Blocking sleep because of: \(String(describing: blockingObjects.first))"
var logString: String = "Blocking sleep because of: \(String(describing: blockingObjects.first))" // stringlint:disable
if blockingObjects.count > 1 {
logString = "\(logString) (and \(blockingObjects.count - 1) others)"
@ -209,7 +209,7 @@ final class MainAppContext: AppContext {
// b) modified time before app launch time.
let filePath: String = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName).path
if !fileName.hasPrefix("ows_temp") {
if !fileName.hasPrefix("ows_temp") { // stringlint:disable
// It's fine if we can't get the attributes (the file may have been deleted since we found it),
// also don't delete files which were created in the last N minutes
guard

@ -13,10 +13,10 @@ public struct SessionApp {
static var versionInfo: String {
let buildNumber: String = (Bundle.main.infoDictionary?["CFBundleVersion"] as? String)
.map { " (\($0))" }
.map { " (\($0))" } // stringlint:disable
.defaulting(to: "")
let appVersion: String? = (Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String)
.map { "App: \($0)\(buildNumber)" }
.map { "App: \($0)\(buildNumber)" } // stringlint:disable
#if DEBUG
let commitInfo: String? = (Bundle.main.infoDictionary?["GitCommitHash"] as? String).map { "Commit: \($0)" }
#else
@ -24,9 +24,9 @@ public struct SessionApp {
#endif
let versionInfo: [String] = [
"iOS \(UIDevice.current.systemVersion)",
"iOS \(UIDevice.current.systemVersion)", // stringlint:disable
appVersion,
"libSession: \(SessionUtil.libSessionVersion)",
"libSession: \(SessionUtil.libSessionVersion)", // stringlint:disable
commitInfo
].compactMap { $0 }

@ -176,7 +176,7 @@ public enum PushRegistrationError: Error {
// so the user doesn't remain indefinitely hung for no good reason.
return Fail(
error: PushRegistrationError.pushNotSupported(
description: "Device configuration disallows push notifications"
description: "Device configuration disallows push notifications" // stringlint:disable
)
).eraseToAnyPublisher()
@ -282,7 +282,7 @@ public enum PushRegistrationError: Error {
let caller: String = payload["caller"] as? String,
let timestampMs: Int64 = payload["timestamp"] as? Int64
else {
SessionCallManager.reportFakeCall(info: "Missing payload data")
SessionCallManager.reportFakeCall(info: "Missing payload data") // stringlint:disable
return
}
@ -327,7 +327,7 @@ public enum PushRegistrationError: Error {
}
guard let call: SessionCall = maybeCall else {
SessionCallManager.reportFakeCall(info: "Could not retrieve call from database")
SessionCallManager.reportFakeCall(info: "Could not retrieve call from database") // stringlint:disable
return
}
@ -345,6 +345,6 @@ public enum PushRegistrationError: Error {
// We transmit pushToken data as hex encoded string to the server
fileprivate extension Data {
var hexEncodedString: String {
return map { String(format: "%02hhx", $0) }.joined()
return map { String(format: "%02hhx", $0) }.joined() // stringlint:disable
}
}

@ -39,12 +39,7 @@ final class RegisterVC : BaseVC {
let result = UILabel()
result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .textPrimary
let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy"
let attributedText = NSMutableAttributedString(string: text, attributes: [ .font : UIFont.systemFont(ofSize: Values.verySmallFontSize) ])
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy"))
result.attributedText = attributedText
result.attributedText = "onboardingTosPrivacy".localizedFormatted(in: result)
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0
@ -231,6 +226,7 @@ final class RegisterVC : BaseVC {
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(enableCopyButton), userInfo: nil, repeats: false)
}
// TODO: Will be removed by onboarding redesign
@objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) {
let urlAsString: String?
let tosRange = (legalLabel.text! as NSString).range(of: "Terms of Service")

@ -26,18 +26,8 @@ final class RestoreVC: BaseVC {
private lazy var legalLabel: UILabel = {
let result = UILabel()
result.font = .systemFont(ofSize: Values.verySmallFontSize)
let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy"
let attributedText = NSMutableAttributedString(
string: text,
attributes: [
.font: UIFont.systemFont(ofSize: Values.verySmallFontSize)
]
)
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy"))
result.themeTextColor = .textPrimary
result.attributedText = attributedText
result.attributedText = "onboardingTosPrivacy".localizedFormatted(in: result)
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0
@ -230,6 +220,7 @@ final class RestoreVC: BaseVC {
self.navigationController?.pushViewController(pnModeVC, animated: true)
}
// TODO: Will be removed by onboarding redesign
@objc private func handleLegalLabelTapped(_ tapGestureRecognizer: UITapGestureRecognizer) {
let urlAsString: String?
let tosRange = (legalLabel.text! as NSString).range(of: "Terms of Service")

@ -42,10 +42,10 @@ final class SeedVC: BaseVC {
private lazy var redactedMnemonic: String = {
if isIPhone5OrSmaller {
return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆"
return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆" // stringlint:disable
}
return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆ ▆▆▆▆▆▆▆▆ ▆▆ ▆▆▆ ▆▆▆▆▆▆▆"
return "▆▆▆▆ ▆▆▆▆▆▆ ▆▆▆ ▆▆▆▆▆▆▆ ▆▆ ▆▆▆▆ ▆▆▆ ▆▆▆▆▆ ▆▆▆ ▆ ▆▆▆▆ ▆▆ ▆▆▆▆▆▆▆ ▆▆▆▆▆ ▆▆▆▆▆▆▆▆ ▆▆ ▆▆▆ ▆▆▆▆▆▆▆" // stringlint:disable
}()
// MARK: - Initialization
@ -68,12 +68,12 @@ final class SeedVC: BaseVC {
result.setProgress(0.9, animated: false)
ThemeManager.onThemeChange(observer: result) { [weak result] _, primaryColor in
let title = "You're almost finished! 90%"
let title = "You're almost finished! 90%" // stringlint:disable
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "90%")
range: (title as NSString).range(of: "90%") // stringlint:disable
)
result?.title = attributedTitle
}
@ -234,12 +234,12 @@ final class SeedVC: BaseVC {
UIView.transition(with: seedReminderView.titleLabel, duration: 0.25, options: .transitionCrossDissolve, animations: {
ThemeManager.onThemeChange(observer: self.seedReminderView) { [weak self] _, primaryColor in
let title = "Account Secured! 100%"
let title = "Account Secured! 100%" // stringlint:disable
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "100%")
range: (title as NSString).range(of: "100%") // stringlint:disable
)
self?.seedReminderView.title = attributedTitle
}

@ -219,8 +219,8 @@ final class PathVC: BaseVC {
private func getPathRow(snode: Snode, location: LineView.Location, dotAnimationStartDelay: Double, dotAnimationRepeatInterval: Double, isGuardSnode: Bool) -> UIStackView {
let country: String = (IP2Country.isInitialized ?
IP2Country.shared.countryNamesCache.wrappedValue[snode.ip].defaulting(to: "Resolving...") :
"Resolving..."
IP2Country.shared.countryNamesCache.wrappedValue[snode.ip].defaulting(to: "resolving".localized()) :
"resolving".localized()
)
return getPathRow(

@ -154,7 +154,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
elements: [
SessionCell.Info(
id: .support,
title: "Export Database",
title: "Export Database", // stringlint:disable
rightAccessory: .icon(
UIImage(systemName: "square.and.arrow.up.trianglebadge.exclamationmark")?
.withRenderingMode(.alwaysTemplate),
@ -224,7 +224,7 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
self.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "Export Database",
title: "Export Database", // stringlint:disable
body: .input(
explanation: NSAttributedString(
string: """
@ -235,12 +235,12 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
This password will be used to encrypt the database decryption key and will be exported alongside the database
"""
),
placeholder: "Enter a password",
placeholder: "Enter a password", // stringlint:disable
initialValue: generatedPassword,
clearButton: true,
onChange: { [weak self] value in self?.databaseKeyEncryptionPassword = value }
),
confirmTitle: "Export",
confirmTitle: "Export", // stringlint:disable
dismissOnConfirm: false,
onConfirm: { [weak self] modal in
modal.dismiss(animated: true) {
@ -248,8 +248,8 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "Error",
body: .text("Password must be at least 6 characters")
title: "Error", // stringlint:disable
body: .text("Password must be at least 6 characters") // stringlint:disable
)
),
transitionType: .present
@ -275,14 +275,14 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "Password",
title: "Password", // stringlint:disable
body: .text("""
The generated password was:
\(generatedPassword)
Avoid sending this via the same means as the database
"""),
confirmTitle: "Share",
confirmTitle: "Share", // stringlint:disable
dismissOnConfirm: false,
onConfirm: { [weak self] modal in
modal.dismiss(animated: true) {
@ -319,16 +319,16 @@ class HelpViewModel: SessionTableViewModel, NavigatableStateHolder, ObservableTa
let message: String = {
switch error {
case CryptoKitError.incorrectKeySize:
return "The password must be between 6 and 32 characters (padded to 32 bytes)"
return "The password must be between 6 and 32 characters (padded to 32 bytes)" // stringlint:disable
default: return "Failed to export database"
default: return "Failed to export database" // stringlint:disable
}
}()
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "Error",
title: "Error", // stringlint:disable
body: .text(message)
)
),

@ -37,7 +37,7 @@ class VersionFooterView: UIView {
let version: String = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
let buildNumber: String = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
{
result.text = "Version \(version) (\(buildNumber))"
result.text = "Version \(version) (\(buildNumber))" // stringlint:disable
}
return result

@ -7,7 +7,7 @@ import SessionMessagingKit
import SessionUtilitiesKit
public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticCell {
public static let mutePrefix: String = "\u{e067} "
public static let mutePrefix: String = "\u{e067} " // stringlint:disable
public static let unreadCountViewSize: CGFloat = 20
private static let statusIndicatorSize: CGFloat = 14
@ -105,7 +105,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .conversationButton_unreadBubbleText
result.text = "@"
result.text = "@" // stringlint:disable
result.textAlignment = .center
return result
@ -401,7 +401,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
unreadImageView.isHidden = (!unreadCountView.isHidden || !threadIsUnread)
unreadCountLabel.text = (unreadCount <= 0 ?
"" :
(unreadCount < 10000 ? "\(unreadCount)" : "9999+")
(unreadCount < 10000 ? "\(unreadCount)" : "9999+") // stringlint:disable
)
unreadCountLabel.font = .boldSystemFont(
ofSize: (unreadCount < 10000 ? Values.verySmallFontSize : 8)
@ -526,7 +526,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
if let hasUnread: Bool = hasUnread {
if hasUnread {
unreadCountView.isHidden = false
unreadCountLabel.text = "1"
unreadCountLabel.text = "1" // stringlint:disable
unreadCountLabel.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
accentLineView.alpha = 1
} else {
@ -579,7 +579,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
let authorName: String = cellViewModel.authorName(for: cellViewModel.threadVariant)
result.append(NSAttributedString(
string: "\(authorName): ",
string: "\(authorName): ", // stringlint:disable
attributes: [ .foregroundColor: textColor ]
))
}
@ -624,7 +624,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
guard !content.isEmpty, content != "noteToSelf".localized() else {
return NSMutableAttributedString(
string: (authorName != nil && authorName?.isEmpty != true ?
"\(authorName ?? ""): \(content)" :
"\(authorName ?? ""): \(content)" : // stringlint:disable
content
),
attributes: [ .foregroundColor: textColor ]
@ -666,8 +666,8 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
normalizedSnippet
.ranges(
of: (Singleton.hasAppContext && Singleton.appContext.isRTL ?
"(\(part.lowercased()))(^|[^a-zA-Z0-9])" :
"(^|[^a-zA-Z0-9])(\(part.lowercased()))"
"(\(part.lowercased()))(^|[^a-zA-Z0-9])" : // stringlint:disable
"(^|[^a-zA-Z0-9])(\(part.lowercased()))" // stringlint:disable
),
options: [.regularExpression]
)
@ -702,7 +702,7 @@ public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticC
guard !authorName.isEmpty else { return nil }
let authorPrefix: NSAttributedString = NSAttributedString(
string: "\(authorName): ",
string: "\(authorName): ", // stringlint:disable
attributes: [ .foregroundColor: textColor ]
)

@ -29,7 +29,7 @@ final class ScanQRCodeWrapperVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
title = "Scan QR Code"
title = "qrScan".localized()
// Set up navigation bar if needed
if isPresentedModally {

@ -1,5 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
// stringlint:disable
import Foundation
import SessionUtilitiesKit

@ -44,10 +44,10 @@ final class IP2Country {
let ipAsInt: Int = IPv4.toInt(ip)
guard
let ipv4TableIndex = ipv4Table["network"]?.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }),
let countryID: Int = ipv4Table["registered_country_geoname_id"]?[ipv4TableIndex],
let countryNamesTableIndex = countryNamesTable["geoname_id"]?.firstIndex(of: String(countryID)),
let result: String = countryNamesTable["country_name"]?[countryNamesTableIndex]
let ipv4TableIndex = ipv4Table["network"]?.firstIndex(where: { $0 > ipAsInt }).map({ $0 - 1 }), // stringlint:disable
let countryID: Int = ipv4Table["registered_country_geoname_id"]?[ipv4TableIndex], // stringlint:disable
let countryNamesTableIndex = countryNamesTable["geoname_id"]?.firstIndex(of: String(countryID)), // stringlint:disable
let result: String = countryNamesTable["country_name"]?[countryNamesTableIndex] // stringlint:disable
else {
return "onionRoutingPathUnknownCountry".localized() // Relies on the array being sorted
}

@ -41,7 +41,7 @@ public enum MentionUtilities {
attributes: [NSAttributedString.Key: Any]
) -> NSAttributedString {
guard
let regex: NSRegularExpression = try? NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: [])
let regex: NSRegularExpression = try? NSRegularExpression(pattern: "@[0-9a-fA-F]{66}", options: []) // stringlint:disable
else {
return NSAttributedString(string: string)
}
@ -78,7 +78,7 @@ public enum MentionUtilities {
}()
else { continue }
string = string.replacingCharacters(in: range, with: "@\(targetString)")
string = string.replacingCharacters(in: range, with: "@\(targetString)") // stringlint:disable
lastMatchEnd = (match.range.location + targetString.utf16.count)
mentions.append((

@ -10,12 +10,12 @@ enum QRCode {
static func generate(for string: String, hasBackground: Bool) -> UIImage {
let data = string.data(using: .utf8)
var qrCodeAsCIImage: CIImage
let filter1 = CIFilter(name: "CIQRCodeGenerator")!
let filter1 = CIFilter(name: "CIQRCodeGenerator")! // stringlint:disable
filter1.setValue(data, forKey: "inputMessage")
qrCodeAsCIImage = filter1.outputImage!
guard !hasBackground else {
let filter2 = CIFilter(name: "CIFalseColor")!
let filter2 = CIFilter(name: "CIFalseColor")! // stringlint:disable
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
filter2.setValue(CIColor(color: .black), forKey: "inputColor0")
filter2.setValue(CIColor(color: .white), forKey: "inputColor1")
@ -25,10 +25,10 @@ enum QRCode {
return UIImage(ciImage: scaledQRCodeAsCIImage)
}
let filter2 = CIFilter(name: "CIColorInvert")!
let filter2 = CIFilter(name: "CIColorInvert")! // stringlint:disable
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
qrCodeAsCIImage = filter2.outputImage!
let filter3 = CIFilter(name: "CIMaskToAlpha")!
let filter3 = CIFilter(name: "CIMaskToAlpha")! // stringlint:disable
filter3.setValue(qrCodeAsCIImage, forKey: "inputImage")
qrCodeAsCIImage = filter3.outputImage!

@ -259,7 +259,7 @@ private extension String {
var matchEnd = m1.range.location + m1.range.length
if let displayName: String = Profile.displayNameNoFallback(id: publicKey) {
result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)")
result = (result as NSString).replacingCharacters(in: m1.range, with: "@\(displayName)") // stringlint:disable
mentions.append((range: NSRange(location: m1.range.location, length: displayName.utf16.count + 1), publicKey: publicKey)) // + 1 to include the @
matchEnd = m1.range.location + displayName.utf16.count
}

@ -10,9 +10,9 @@ enum NotificationError: LocalizedError {
public var errorDescription: String? {
switch self {
case .processing(let result): return "Failed to process notification (\(result))"
case .messageProcessing: return "Failed to process message"
case .messageHandling(let error): return "Failed to handle message (\(error))"
case .processing(let result): return "Failed to process notification (\(result))" // stringlint:disable
case .messageProcessing: return "Failed to process message" // stringlint:disable
case .messageHandling(let error): return "Failed to handle message (\(error))" // stringlint:disable
}
}
}

@ -17,10 +17,10 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
private var request: UNNotificationRequest?
private var openGroupPollCancellable: AnyCancellable?
public static let isFromRemoteKey = "remote"
public static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId"
public static let threadVariantRaw = "Signal.AppNotificationsUserInfoKey.threadVariantRaw"
public static let threadNotificationCounter = "Session.AppNotificationsUserInfoKey.threadNotificationCounter"
public static let isFromRemoteKey = "remote" // stringlint:disable
public static let threadIdKey = "Signal.AppNotificationsUserInfoKey.threadId" // stringlint:disable
public static let threadVariantRaw = "Signal.AppNotificationsUserInfoKey.threadVariantRaw" // stringlint:disable
public static let threadNotificationCounter = "Session.AppNotificationsUserInfoKey.threadNotificationCounter" // stringlint:disable
private static let callPreOfferLargeNotificationSupressionDuration: TimeInterval = 30
// MARK: Did receive a remote push notification request
@ -320,9 +320,9 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
guard let caller: String = callMessage.sender, let timestamp = callMessage.sentTimestamp else { return }
let payload: JSON = [
"uuid": callMessage.uuid,
"caller": caller,
"timestamp": timestamp
"uuid": callMessage.uuid, // stringlint:disable
"caller": caller, // stringlint:disable
"timestamp": timestamp // stringlint:disable
]
CXProvider.reportNewIncomingVoIPPushPayload(payload) { error in
@ -352,7 +352,9 @@ public final class NotificationServiceExtension: UNNotificationServiceExtension
if let sender: String = callMessage.sender {
let senderDisplayName: String = Profile.displayName(db, id: sender, threadVariant: .contact)
notificationContent.body = "\(senderDisplayName) is calling..."
notificationContent.body = "callsIncoming"
.put(key: "name", value: senderDisplayName)
.localized()
}
else {
notificationContent.body = "Incoming call..."

@ -473,7 +473,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate {
switch value {
case let data as Data:
let customFileName = "Contact.vcf"
let customFileName = "Contact.vcf" // stringlint:disable
let customFileExtension = MIMETypeUtil.fileExtension(forUTIType: srcUtiType)
guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: customFileExtension) else {
@ -504,7 +504,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate {
)
return
}
guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: "txt") else {
guard let tempFilePath = OWSFileSystem.writeData(toTemporaryFile: data, fileExtension: "txt") else { // stringlint:disable
resolver(
Result.failure(ShareViewControllerError.assertionError(description: "Error writing item data: \(String(describing: error))"))
)
@ -574,7 +574,7 @@ final class ShareNavController: UINavigationController, ShareViewDelegate {
case let image as UIImage:
if let data = image.pngData() {
let tempFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: "png")
let tempFilePath = OWSFileSystem.temporaryFilePath(withFileExtension: "png") // stringlint:disable
do {
let url = NSURL.fileURL(withPath: tempFilePath)
try data.write(to: url)

@ -212,7 +212,7 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
(
(messageText?.isEmpty == true || (attachments[0].text() == messageText) ?
attachments[0].text() :
"\(attachments[0].text() ?? "")\n\n\(messageText ?? "")"
"\(attachments[0].text() ?? "")\n\n\(messageText ?? "")" // stringlint:disable
)
) :
messageText

Loading…
Cancel
Save