Skip to content

Commit 72ac1d4

Browse files
committed
WIP
Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>
1 parent 0c87881 commit 72ac1d4

File tree

4 files changed

+43
-108
lines changed

4 files changed

+43
-108
lines changed

Nextcloud.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
F343A4B32A1E01FF00DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
113113
F343A4B62A1E084200DDA874 /* PHAsset+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */; };
114114
F343A4BB2A1E734600DDA874 /* Optional+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */; };
115+
F34BDB3A2F5744EC007A222C /* UINavigationItem+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34BDB392F5744E5007A222C /* UINavigationItem+Extension.swift */; };
115116
F34E1AD72ECB937D00FA10C3 /* NCStatusMessageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34E1AD62ECB937D00FA10C3 /* NCStatusMessageView.swift */; };
116117
F34E1AD92ECC839100FA10C3 /* EmojiTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34E1AD82ECC839100FA10C3 /* EmojiTextField.swift */; };
117118
F34E1ADB2ECC842B00FA10C3 /* NCStatusMessageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F34E1ADA2ECC842200FA10C3 /* NCStatusMessageModel.swift */; };
@@ -1244,6 +1245,7 @@
12441245
F33EE6F12BF4C9B200CA1A51 /* PKCS12.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PKCS12.swift; sourceTree = "<group>"; };
12451246
F343A4B22A1E01FF00DDA874 /* PHAsset+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PHAsset+Extension.swift"; sourceTree = "<group>"; };
12461247
F343A4BA2A1E734600DDA874 /* Optional+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Optional+Extension.swift"; sourceTree = "<group>"; };
1248+
F34BDB392F5744E5007A222C /* UINavigationItem+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationItem+Extension.swift"; sourceTree = "<group>"; };
12471249
F34E1AD62ECB937D00FA10C3 /* NCStatusMessageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCStatusMessageView.swift; sourceTree = "<group>"; };
12481250
F34E1AD82ECC839100FA10C3 /* EmojiTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiTextField.swift; sourceTree = "<group>"; };
12491251
F34E1ADA2ECC842200FA10C3 /* NCStatusMessageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCStatusMessageModel.swift; sourceTree = "<group>"; };
@@ -2815,6 +2817,7 @@
28152817
F7A0D14E259229FA008F8A13 /* Extensions */ = {
28162818
isa = PBXGroup;
28172819
children = (
2820+
F34BDB392F5744E5007A222C /* UINavigationItem+Extension.swift */,
28182821
F7AC1CAF28AB94490032D99F /* Array+Extension.swift */,
28192822
F7817CF729801A3500FFBC65 /* Data+Extension.swift */,
28202823
AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */,
@@ -4560,6 +4563,7 @@
45604563
F3A047972BD2668800658E7B /* NCAssistantEmptyView.swift in Sources */,
45614564
F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */,
45624565
F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */,
4566+
F34BDB3A2F5744EC007A222C /* UINavigationItem+Extension.swift in Sources */,
45634567
F7F3E58E2D3BB65600A32B14 /* NCNetworking+Recommendations.swift in Sources */,
45644568
F7A0D1352591FBC5008F8A13 /* String+Extension.swift in Sources */,
45654569
F7CEE6012BA9A5C9003EFD89 /* NCTrashGridCell.swift in Sources */,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-FileCopyrightText: Nextcloud GmbH
2+
// SPDX-FileCopyrightText: 2026 Milen Pivchev
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
extension UINavigationItem {
6+
/// Sets the navigation title using a custom titleView with two labels (base + extension)
7+
/// to prevent Unicode bidi override attacks from visually disguising the real file extension.
8+
func setBidiSafeTitle(_ filename: String) {
9+
let nsName = filename as NSString
10+
let ext = nsName.pathExtension
11+
let base = nsName.deletingPathExtension
12+
13+
if ext.isEmpty || base.isEmpty {
14+
self.titleView = nil
15+
self.title = filename
16+
} else {
17+
let baseLabel = UILabel()
18+
baseLabel.text = base
19+
baseLabel.font = .systemFont(ofSize: 17, weight: .semibold)
20+
baseLabel.lineBreakMode = .byTruncatingMiddle
21+
baseLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
22+
baseLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
23+
24+
let extLabel = UILabel()
25+
extLabel.text = "." + ext
26+
extLabel.font = .systemFont(ofSize: 17, weight: .semibold)
27+
extLabel.setContentHuggingPriority(.required, for: .horizontal)
28+
extLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
29+
30+
let stack = UIStackView(arrangedSubviews: [baseLabel, extLabel])
31+
stack.axis = .horizontal
32+
stack.alignment = .firstBaseline
33+
stack.spacing = 0
34+
35+
self.titleView = stack
36+
self.title = nil
37+
}
38+
}
39+
}

iOSClient/Extensions/UIView+Extension.swift

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -54,38 +54,3 @@ extension UIView {
5454
}
5555
}
5656
}
57-
extension UINavigationItem {
58-
/// Sets the navigation title using a custom titleView with two labels (base + extension)
59-
/// to prevent Unicode bidi override attacks from visually disguising the real file extension.
60-
func setBidiSafeTitle(_ filename: String) {
61-
let nsName = filename as NSString
62-
let ext = nsName.pathExtension
63-
let base = nsName.deletingPathExtension
64-
65-
if ext.isEmpty || base.isEmpty {
66-
self.titleView = nil
67-
self.title = filename
68-
} else {
69-
let baseLabel = UILabel()
70-
baseLabel.text = base
71-
baseLabel.font = .systemFont(ofSize: 17, weight: .semibold)
72-
baseLabel.lineBreakMode = .byTruncatingMiddle
73-
baseLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
74-
baseLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
75-
76-
let extLabel = UILabel()
77-
extLabel.text = "." + ext
78-
extLabel.font = .systemFont(ofSize: 17, weight: .semibold)
79-
extLabel.setContentHuggingPriority(.required, for: .horizontal)
80-
extLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
81-
82-
let stack = UIStackView(arrangedSubviews: [baseLabel, extLabel])
83-
stack.axis = .horizontal
84-
stack.alignment = .firstBaseline
85-
stack.spacing = 0
86-
87-
self.titleView = stack
88-
self.title = nil
89-
}
90-
}
91-
}

iOSClient/Main/Collection Common/Cell/NCListCell.swift

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -317,79 +317,6 @@ class NCListLayout: UICollectionViewFlowLayout {
317317
}
318318
}
319319

320-
class BidiFilenameLabel: UILabel {
321-
var fullFilename: String = ""
322-
323-
var isFolder: Bool = false
324-
325-
var isRTL: Bool = false
326-
327-
override init(frame: CGRect) {
328-
super.init(frame: frame)
329-
}
330-
331-
required init?(coder: NSCoder) {
332-
super.init(coder: coder)
333-
}
334-
335-
override func layoutSubviews() {
336-
super.layoutSubviews()
337-
updateText()
338-
}
339-
340-
private func updateText() {
341-
guard !fullFilename.isEmpty else {
342-
self.text = ""
343-
return
344-
}
345-
346-
let availableWidth = bounds.width
347-
guard availableWidth > 0 else { return }
348-
349-
let isRTL = UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft
350-
let sanitizedFilename = fullFilename.sanitizeForBidiCharacters(isFolder: isFolder, isRTL: isRTL)
351-
352-
let nsFilename = sanitizedFilename as NSString
353-
let ext = nsFilename.pathExtension
354-
let base = nsFilename.deletingPathExtension
355-
356-
let dotExt = ext.isEmpty ? "" : "." + ext
357-
let truncatedBase = truncateBase(base: base, dotExt: dotExt, maxWidth: availableWidth, font: font ?? UIFont.systemFont(ofSize: 17))
358-
359-
self.text = sanitizedFilename.replacingOccurrences(of: base, with: truncatedBase)
360-
}
361-
362-
private func truncateBase(base: String, dotExt: String, maxWidth: CGFloat, font: UIFont) -> String {
363-
let extWidth = (dotExt as NSString).size(withAttributes: [.font: font]).width
364-
365-
if (base as NSString).size(withAttributes: [.font: font]).width + extWidth <= maxWidth {
366-
return base
367-
}
368-
369-
let characters = Array(base)
370-
var low = 0
371-
var high = characters.count
372-
var result = ""
373-
374-
while low <= high {
375-
let mid = (low + high) / 2
376-
let prefixCount = mid / 2
377-
let suffixCount = mid - prefixCount
378-
let finalString = String(characters.prefix(prefixCount)) + "" + String(characters.suffix(suffixCount))
379-
let finalStringWidth = (finalString as NSString).size(withAttributes: [.font: font]).width + extWidth
380-
381-
if finalStringWidth <= maxWidth {
382-
result = finalString
383-
low = mid + 1
384-
} else {
385-
high = mid - 1
386-
}
387-
}
388-
389-
return result
390-
}
391-
}
392-
393320
#if !EXTENSION
394321
extension NCCollectionViewCommon {
395322
func listCell(cell: NCListCell, indexPath: IndexPath, metadata: tableMetadata) -> NCListCell {

0 commit comments

Comments
 (0)