Skip to content

Commit 64c4678

Browse files
NMC 1997 - Sharing customisation changes
1 parent 4a257ea commit 64c4678

35 files changed

Lines changed: 1747 additions & 1816 deletions

Tests/NextcloudUnitTests/SharingTest.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -201,32 +201,32 @@ final class SharingTest: XCTestCase {
201201
}
202202

203203
func testGetImageShareType() {
204-
let sut = NCShareCommon() // Replace with the actual class containing the getImageShareType function
204+
let sut = NCShareCommon // Replace with the actual class containing the getImageShareType function
205205

206206
// Test case 1: SHARE_TYPE_USER
207-
let shareType1 = sut.SHARE_TYPE_USER
207+
let shareType1 = sut.shareTypeUser
208208
let result1 = sut.getImageShareType(shareType: shareType1)
209209
XCTAssertEqual(result1, UIImage(named: "shareTypeEmail")?.imageColor(NCBrandColor.shared.label))
210210

211211
// Test case 2: SHARE_TYPE_GROUP
212-
let shareType2 = sut.SHARE_TYPE_GROUP
212+
let shareType2 = sut.shareTypeGroup
213213
let result2 = sut.getImageShareType(shareType: shareType2)
214214
XCTAssertEqual(result2, UIImage(named: "shareTypeGroup")?.imageColor(NCBrandColor.shared.label))
215215

216216
// Test case 3: SHARE_TYPE_LINK
217-
let shareType3 = sut.SHARE_TYPE_LINK
217+
let shareType3 = sut.shareTypeLink
218218
let result3 = sut.getImageShareType(shareType: shareType3)
219219
XCTAssertEqual(result3, UIImage(named: "shareTypeLink")?.imageColor(NCBrandColor.shared.label))
220220

221221
// Test case 4: SHARE_TYPE_EMAIL (with isDropDown=false)
222-
let shareType4 = sut.SHARE_TYPE_EMAIL
222+
let shareType4 = sut.shareTypeEmail
223223
let result4 = sut.getImageShareType(shareType: shareType4)
224224
XCTAssertEqual(result4, UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label))
225225

226226
// Test case 5: SHARE_TYPE_EMAIL (with isDropDown=true)
227-
let shareType5 = sut.SHARE_TYPE_EMAIL
227+
let shareType5 = sut.shareTypeEmail
228228
let isDropDown5 = true
229-
let result5 = sut.getImageShareType(shareType: shareType5, isDropDown: isDropDown5)
229+
let result5 = sut.getImageShareType(shareType: shareType5)//, isDropDown: isDropDown5)
230230
XCTAssertEqual(result5, UIImage(named: "email")?.imageColor(NCBrandColor.shared.label))
231231
}
232232
}

iOSClient/Activity/NCActivity.swift

Lines changed: 102 additions & 69 deletions
Large diffs are not rendered by default.

iOSClient/Extensions/DateFormatter+Extension.swift

Lines changed: 60 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,69 @@ extension DateFormatter {
2828
static let shareExpDate: DateFormatter = {
2929
let dateFormatter = DateFormatter()
3030
dateFormatter.formatterBehavior = .behavior10_4
31-
// dateFormatter.locale = Locale.current
3231
dateFormatter.dateStyle = .medium
33-
dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
3432
return dateFormatter
3533
}()
36-
}
3734

38-
extension Date {
39-
static var tomorrow: Date { return Date().dayAfter }
40-
static var today: Date {return Date()}
41-
static var dayAfterYear: Date { return Date().dateAfterYear }
42-
var dayAfter: Date {
43-
return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
44-
}
45-
var dateAfterYear: Date {
46-
return Calendar.current.date(byAdding: .year, value: 1, to: Date())!
35+
// static func formattedExpiryDate(_ date: Date) -> String {
36+
// // Get the app language
37+
// let appLanguage = Locale.preferredLanguages.first?.prefix(2) ?? "en"
38+
// let locale = Locale(identifier: "\(appLanguage)_\(appLanguage.uppercased())")
39+
//
40+
// // Extract components
41+
// let calendar = Calendar.current
42+
// let day = calendar.component(.day, from: date)
43+
//
44+
// // Get month name abbreviation in the correct locale
45+
// let monthFormatter = DateFormatter()
46+
// monthFormatter.locale = locale
47+
// monthFormatter.dateFormat = "MMM" // abbreviated month
48+
// var month = monthFormatter.string(from: date)
49+
//
50+
// // Capitalize first letter (German months are lowercase normally)
51+
// month = month.prefix(1).uppercased() + month.dropFirst()
52+
//
53+
// // Remove trailing period if present (common in German abbreviations)
54+
// month = month.replacingOccurrences(of: ".", with: "")
55+
//
56+
// // Get year
57+
// let year = calendar.component(.year, from: date)
58+
//
59+
// return String(format: "%02d.%@.%d", day, month, year)
60+
// }
61+
62+
/// Formats a given Date object into the specific string format "dd. MMM. yyyy"
63+
/// required for the expiry date display (e.g., "01. Dez. 2026").
64+
static func formattedExpiryDate(_ date: Date) -> String {
65+
66+
// 1. Determine the correct locale to use based on the app's preferences
67+
let appLanguageCode = Locale.preferredLanguages.first?.prefix(2) ?? "en"
68+
// Use a standard locale identifier for consistency across devices
69+
let localeIdentifier = (appLanguageCode == "de" || appLanguageCode == "en") ? appLanguageCode : "en"
70+
let locale = Locale(identifier: String(localeIdentifier))
71+
72+
let calendar = Calendar.current
73+
let day = calendar.component(.day, from: date)
74+
let year = calendar.component(.year, from: date)
75+
76+
// 2. Get the month abbreviation using the correct locale
77+
let monthFormatter = DateFormatter()
78+
monthFormatter.locale = locale
79+
monthFormatter.dateFormat = "MMM" // e.g., "Dez." (German locale adds a period) or "Dec" (English locale adds no period)
80+
var month = monthFormatter.string(from: date)
81+
82+
// 3. CRITICAL FIXES:
83+
// A. Remove any trailing period the locale might have added
84+
month = month.replacingOccurrences(of: ".", with: "")
85+
86+
// B. Capitalize the first letter (German defaults to lowercase 'dez')
87+
month = month.prefix(1).uppercased() + month.dropFirst()
88+
89+
// 4. Use the String(format:) with correct spacing to guarantee the output structure
90+
// This line guarantees a SINGLE period after the day and a SINGLE period after the month abbreviation.
91+
let formattedDateString = String(format: "%02d. %@. %d", day, month, year)
92+
93+
return formattedDateString
4794
}
95+
4896
}

iOSClient/Extensions/UIButton+Extension.swift

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,12 @@ extension UIButton {
2525
}
2626

2727
func hideSpinnerAndShowButton() {
28-
let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
29-
let spinner = self.superview?.subviews.first(where: { view -> Bool in
30-
return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
31-
})
28+
let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
29+
let spinner = self.superview?.subviews.first(where: { view -> Bool in
30+
return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
31+
})
3232

33-
spinner?.removeFromSuperview()
34-
self.isHidden = false
35-
}
36-
37-
func setBackgroundColor(_ color: UIColor, for forState: UIControl.State) {
38-
UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
39-
UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
40-
UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
41-
let colorImage = UIGraphicsGetImageFromCurrentImageContext()
42-
UIGraphicsEndImageContext()
43-
self.setBackgroundImage(colorImage, for: forState)
44-
}
33+
spinner?.removeFromSuperview()
34+
self.isHidden = false
35+
}
4536
}

iOSClient/Extensions/UIToolbar+Extension.swift

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extension UIToolbar {
3737
buttons.append(clearButton)
3838
}
3939
buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
40-
let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
40+
let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain) {
4141
onDone()
4242
}
4343
buttons.append(doneButton)
@@ -58,20 +58,6 @@ extension UIToolbar {
5858
])
5959
return view
6060
}
61-
62-
static func doneToolbar(completion: @escaping () -> Void) -> UIToolbar {
63-
let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
64-
doneToolbar.barStyle = .default
65-
66-
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
67-
let done: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
68-
completion()
69-
}
70-
let items = [flexSpace, done]
71-
doneToolbar.items = items
72-
doneToolbar.sizeToFit()
73-
return doneToolbar
74-
}
7561
}
7662

7763
// https://stackoverflow.com/a/67985180/9506784

iOSClient/Extensions/UIView+Extension.swift

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,6 @@
2424
import Foundation
2525
import UIKit
2626

27-
enum VerticalLocation: String {
28-
case bottom
29-
case top
30-
}
31-
3227
extension UIView {
3328

3429
// Source
@@ -74,21 +69,42 @@ extension UIView {
7469
self.layer.cornerRadius = self.frame.size.width / 2
7570
self.layer.masksToBounds = true
7671
}
77-
78-
func addShadow(location: VerticalLocation, height: CGFloat = 2, color: UIColor = NCBrandColor.shared.customerDarkGrey, opacity: Float = 0.4, radius: CGFloat = 2) {
79-
switch location {
80-
case .bottom:
81-
addShadow(offset: CGSize(width: 0, height: height), color: color, opacity: opacity, radius: radius)
82-
case .top:
83-
addShadow(offset: CGSize(width: 0, height: -height), color: color, opacity: opacity, radius: radius)
72+
73+
var parentTabBarController: UITabBarController? {
74+
var responder: UIResponder? = self
75+
while let nextResponder = responder?.next {
76+
if let tabBarController = nextResponder as? UITabBarController {
77+
return tabBarController
78+
}
79+
responder = nextResponder
8480
}
81+
return nil
8582
}
8683

87-
func addShadow(offset: CGSize, color: UIColor = .black, opacity: Float = 0.5, radius: CGFloat = 5.0) {
88-
self.layer.masksToBounds = false
89-
self.layer.shadowColor = color.cgColor
90-
self.layer.shadowOffset = offset
91-
self.layer.shadowOpacity = opacity
92-
self.layer.shadowRadius = radius
84+
func addBlur(style: UIBlurEffect.Style, alpha: CGFloat = 1.0) {
85+
let blurEffect = UIBlurEffect(style: style)
86+
let blurView = UIVisualEffectView(effect: blurEffect)
87+
blurView.frame = bounds
88+
blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
89+
blurView.alpha = alpha
90+
blurView.layer.masksToBounds = true
91+
insertSubview(blurView, at: 0)
92+
}
93+
94+
func addBlurBackground(style: UIBlurEffect.Style, alpha: CGFloat = 1) {
95+
let blur = UIBlurEffect(style: style)
96+
let blurView = UIVisualEffectView(effect: blur)
97+
blurView.isUserInteractionEnabled = false
98+
blurView.alpha = alpha
99+
blurView.layer.masksToBounds = true
100+
blurView.translatesAutoresizingMaskIntoConstraints = false
101+
insertSubview(blurView, at: 0)
102+
103+
NSLayoutConstraint.activate([
104+
blurView.topAnchor.constraint(equalTo: topAnchor),
105+
blurView.leadingAnchor.constraint(equalTo: leadingAnchor),
106+
blurView.trailingAnchor.constraint(equalTo: trailingAnchor),
107+
blurView.bottomAnchor.constraint(equalTo: bottomAnchor)
108+
])
93109
}
94110
}

0 commit comments

Comments
 (0)