From e342f87b0e421e6f98686f50e9ffc8fcbf824447 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:58:19 +0530 Subject: [PATCH 1/5] NMC 1984 - Privacy policy customisation added --- .../dataPrivacy.imageset/Contents.json | 23 ++ .../dataPrivacy.imageset/default copy@2x.png | Bin 0 -> 1262 bytes .../dataPrivacy.imageset/default copy@3x.png | Bin 0 -> 2037 bytes .../dataPrivacy.imageset/default copy@4x.png | Bin 0 -> 2624 bytes .../NCCollectionViewCommon.swift | 21 ++ .../AnalysisDataCollectionSwitch.swift | 34 +++ .../Settings/AnalysisDataCollectionSwitch.xib | 73 ++++++ ...InitialPrivacySettingsViewController.swift | 170 +++++++++++++ iOSClient/Settings/NCSettings.storyboard | 236 ++++++++++++++++++ .../PrivacyPolicyViewController.swift | 62 +++++ .../PrivacySettingsViewController.swift | 133 ++++++++++ .../RequiredDataCollectionSwitch.swift | 34 +++ .../Settings/RequiredDataCollectionSwitch.xib | 73 ++++++ .../SaveSettingsCustomButtonCell.swift | 46 ++++ .../Settings/SaveSettingsCustomButtonCell.xib | 46 ++++ 15 files changed, 951 insertions(+) create mode 100644 iOSClient/Images.xcassets/dataPrivacy.imageset/Contents.json create mode 100644 iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@2x.png create mode 100644 iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@3x.png create mode 100644 iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@4x.png create mode 100644 iOSClient/Settings/AnalysisDataCollectionSwitch.swift create mode 100644 iOSClient/Settings/AnalysisDataCollectionSwitch.xib create mode 100644 iOSClient/Settings/InitialPrivacySettingsViewController.swift create mode 100644 iOSClient/Settings/NCSettings.storyboard create mode 100644 iOSClient/Settings/PrivacyPolicyViewController.swift create mode 100644 iOSClient/Settings/PrivacySettingsViewController.swift create mode 100644 iOSClient/Settings/RequiredDataCollectionSwitch.swift create mode 100644 iOSClient/Settings/RequiredDataCollectionSwitch.xib create mode 100644 iOSClient/Settings/SaveSettingsCustomButtonCell.swift create mode 100644 iOSClient/Settings/SaveSettingsCustomButtonCell.xib diff --git a/iOSClient/Images.xcassets/dataPrivacy.imageset/Contents.json b/iOSClient/Images.xcassets/dataPrivacy.imageset/Contents.json new file mode 100644 index 0000000000..4fb0d4c09c --- /dev/null +++ b/iOSClient/Images.xcassets/dataPrivacy.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "default copy@2x.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "default copy@3x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "default copy@4x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@2x.png b/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..40c3e7d47f2c2fdbdc87713870b113c36d2bbc07 GIT binary patch literal 1262 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NGSV=@dRA>e5naPV4R}{wkIf1Ao z5ETSbL~s#eB7z#VK@nFX?NU*9iDKMmoppq41lN*(AQ}`zT`5kjAWpQPIDkV2g9?$D zIHdFYy6Y4tRrgxAhVFLZf$!Z@x6b#Sb8ZdqRlUBx4>qwY(Cae&@bK_d^p=4&4oY#( z;YzR9d#%YXtW^UPJewj`11oq1{`88%Ub6oZu%^z_&>t0?=Hkd&&H*Ulfk>}IXf=^ zHFF*e($JrbB?~q{@mGla3{)k0LCheqVlTuJ5i?@h!e}w9DJ{~>(Y?`6EzAwHb$$KM zVhzL&-$U41UBgvGCEnO*NQ?9ZP(z0KAwhBl>n+71>g@m<+rh$8;22FPSC&(`a|@*l zb|i)cCwFaxj>oE6CUu-|+~qzrFz!oUNH``(fb(`UI1YZzAb)cq_tC!Be}>~V4(FfJR5@$+P2$AQZ2>bM$`k6pySyWly_A8*&^eiBL^ zYrr2aJ%mS%75WJL0PX>^pK$b!XvE|L&6(Z9*$1kgg?;WvrdK&4{53E;93v2*yUw5m z7RHe#m@5|V!%nj??H&4uUGVN$TxlNCB1e3RA3Rdb?{#q@S55ep55;^{Du4+BCjsR) zTM~+k&cV84Oh&y1DH-!8Tuf8Q0Rf1ro?!(9M$cNa=3iA@uRodq|6Ac2md zYw$YRq>*VcjF@hp`uC@MLwL_Tv$r^VQtN0HN1|QewPnsmz5lHI!KE0WSZ{iS9ov;Jc1*$zz#o1U^bhzRl&%fU zW&0H4O^>hrMg4KvCh=V0f3sU*y4a5Zy`>i9Yp!VG>c8fRHHz2-^sSj{cM04wu~iqc zQ_vK!16%_!yTuM&Kl$TkLFWC~q`-clZ*P4e>D9`QU?T|rsrY_W9jJnWCxa=0U7bz+ Y2SkK6zRJ=a>Hq)$07*qoM6N<$g2I134*&oF literal 0 HcmV?d00001 diff --git a/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@3x.png b/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..74d9dbb7dd8e51db1844e2102dff7045c235a1fb GIT binary patch literal 2037 zcmVPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91NT34%1ONa40RR91NB{r;0FW_8?*IS?Ur9tkRCodHn{TXFa~#LJLd_y{ zMZ^}8G@*Y&>~7Q(tF1iI^x!h{$e*z+p5dAC#0+a>nR$@4qHI=AG}TQcim5Bg5W|(4 zq+7SH*Zb$3+d1F+J?DG=pL_Xzw)g%1{d_*}@B4TDpL2%{Xfe=HnCjx)#P&uKXRdo`_-@;VxLbTq3Vu!*MCJ=&*Ao7jC7i1>&b3@t6YaAr> zN5B_tD}o&^B3)*I5M&$#d@)pB3x?((^)>6=B=mfaQEme|7&pKIy1cPQLC#hxI%xZtM*YmjV75QM;MOM?^-sy!oh_8- z1YTK=vqQ?dJV3??6P5V8bb< z18rdvOYoMk zfq7rZaPMmRmmt(Pl(krG#~>DeJ1f==>jGekBQeycv2EU5^;K@Q2*iSQ&$J4ROt50j zS>^d8m|pCZS_EPV&w+DNEJbtWQ@K?x5L?1Uta4t4mCo~gGq`4VsaznawgKBQ$F&Oi z$hT6fL!hxaR+z^(Q`$NN%ChzNi_7Ed$4FJyA<)mM7=|ZTe&JY$KwHCWPSw&2#7eDl zfw(Hx^XkqFtK5gL9(26PFeFDpzNWp-p~d&d*qu*Mya z_A)-3xu0jrVezqXx2>_y)g_Sa1Aq(qymMAq_)bFH03HT9yJ>4V1a!7~3`}N@?)Zx` z8~0d&T+f3_6-cW_fWIkp0IuR7Y!k?~Mp0{+YYW=%PYjf{B!S@pUA1xlF^;iIARPlt z8*O$BqPC6ucX9k(0!iKDMgV;Wl*%}J3@)V_d(4F&)g8PtbId z$Y(@*B^c4Gk4X}hxvk(^i@(_w5{W^VIKKavRP?mbY0MkrI|a&RE=SicCVzd&VOpEn z5z$^u|K$;5!R|9?tbn+L(Jr?FsLy4Sn4n99B-Un`l>g=z!j}aU_p3`S$wFOBYysc< z4hc(bNpZWCEsSnwzHTD>DQv4RFUX9M$; zE_(WeFZRB%GxN9sZZIhF3*R2+RS;O=h(J0t?Ef zp&VW=ijW}GwopH2F4s)$WbG*5>vlK%O+s$9|otGN|$vpp?%N@5l57ToCjV4 zQ3r5_5}Quz%Rp;f&OtfGqOJ$}#}wPO3*An8pBXa-<>J$jW|3Ee*MaTciSCf;x@I+) znI^}7VlImw10DrifoXbn{1g~l=VAxUvt)$O^BR5FsVnX^ytCR~r!dXj2^IJUOCpgG TJQa3{00000NkvXXu0mjfv1qa| literal 0 HcmV?d00001 diff --git a/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@4x.png b/iOSClient/Images.xcassets/dataPrivacy.imageset/default copy@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..682122c3f21e9c196b2df4c47179f97e87b9788b GIT binary patch literal 2624 zcmV-G3cvMPx#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91V4wp41ONa40RR91U;qFB0I4%yP5=N2s!2paRCodHok^?|RTPGKf+#3Y zFc_SIKtPQX4iU%bMx#d5#5e#NbYWt2;l@Oa!Hq*q+!&2R^3~5tNQk{Px7a_Pn~Wa^m(Y+^X4A0R zN*X}14}j(wpt0a%!cwo?+d3ljH-yih(3EYVqXuaJ1wR5}>7hhLSMi62CW}99sh@)n z6D(jUIUk&t;AECn>{;9K`w2*!qLcetzLyg322gAzcM3?iZWVrfDHis@8(Fm&sNgF0 zM|sC;`03oD^GVtioo5aPRmf_b>Ku|bWf}amkvNNU14!(CysGF^KvfC-h;J1--NHZf zO^C5gl58-OQKox{8go>WQMfPKU_J&5;eD@*Tb~AmzHHkK!N$YMhmc<5Lb|LCO*sZ1 zX+yNsVQas#ejCS=i&Jf#jN};7WgD;wH|gO-Teyy)f5~^dh17cCphIce6dkq>D#I&= z2K+<<>7hhRJtEjyCaJo{(vTs<(j$+wAzB{k6Tj{T=y37{NDICI0)0M&W4EO#gBQ90Iza|H`Xn8#|W3) zdS){XTn6+=JblTdmnX}>Ti|)F!J~M_1eb7Pyxp_hgoKN_&l6$x19ySnL7vD)wzcft zHZq}Wu=i=GDOm78Ee?s<3*Iut&e3U%_Lxe=#vypn+5$B&C+1*Kr1&XajjiJKWIxL^ zQ0ubaAk>G}0O|Ko{!M;}F)NKzVmZs?JCx4G%hi9h593H|6iH}mNZGkUngcX}6Z0Rg zMe(sy15EY<;bGjhBv!Wgs*QZeSCmrAl|sSHFE2RGG%TbqlmEiHm>ZxsPN5{EuTY%! z`iZ##hX>3wq_2RqGTvzhjZ(~+^96!~`;fjI!nvEoya%jzPb1edq_5myJ_a#2;5(m0 za%}r@*0*hS%ng_yuqy8d^cB=q%nf)mV5aW`^cB=qv<=`+@>4R^%;U168F`w$9Hm6t zfTUUv1*qD?0erOIMcIc=MKd7o3%1w}dcB~jRBRlA2dyno3v=R*24CCaXXw|k?x+@b z!N1z#R}pBFCD^dw!CD*=_h_)v65pi$0p-LNH^ILWW0)y8y3MY^e9i%y-*1wGOv;ct zPNF~H?{x5tgWnghnar4#4z^`YY`NQNRXiSDU2W<1*y3LON5bJG@F@5c`~fzArQmUJ zn!m^5BZxN^m}E_Hua=QS`P>uJ~5;tOvV6 zqkP5}{rQ?qkqubZIFQfsC7e?HKaOrB&mfx)KY zn|v-tsXwPsSQy^}l)Fhv`8JXwiY7^IG(|%<$vDVC$=D0QcHk<;CNNmV*E&~GE`={! z89T`mXe;{t9a8rr_H3384;-|j9=Y#&xh_^6qX6mG6 zslP+yEI#J|Iki0=)@@)&~-Eih2`9`i_Ch1Ypu9w>4@ax~*+gCb(fc}WpxPGd;+ zik5DtUv(_>nuCeG?JhF)>9W+G;B(k9`PALC*YhmwbvU*i|F3Z>W)UNT4hNfoNiOj5 zi38g%Z1P>TPQN*D7RX#+A*6Fzud^czy$(S<;L=mRcP#;?Tl6+{;S-?EVF~?No?~sf zen5@9ejMV}fQ0007P8anzR#{~yN0&7uT<^KCCSm&fH!@)<@-;21~ptq@< zleRessQ2Nb98G^4V>kMj19GyvVk>wBm}G%{)WBFn(hE$9qkFry3<-9Lg@n{zC*#^k z2MDCxGV;DYKnOP%kkD=TDhru8ZeBXiihSo-a@Nh{0kvjCz^tDSO{tYk4Z+BFilz8c zKTrdO<`4w!1-6@!XeUB7XW{;hTo(e9XtILt#_JaX&o(hibTjH_R82(knURs_Bh^H8 z@CvD{y+9ATMmV^M+C(`3$!cQ-ANlsE%%w@F;*I9R@DV~Sp{ z8$0HFAg&2#7Dky{pr_Rif#wn57bD$$O5MZ^sg^}~@8Sq-H(bg@?+^4MCq9ALm13A7 zPsYc(nGxKd%;2w8H#U!m>>C81$VuRy$SC*If%iQ*+@I?=j`afxXv+5Tj6`;`F1oEq zoPfC5L{nLO-gmUGMG!p}{AtSs{Vs54`xrJy7MFw*3#0U*9n(B2@^28qP*#mo{F-}dgeE~;VTkjU*>nI`LWeO=w0nj{s)0E(3*ntF42nCv6* zLP9ryZCP0->t13R{Ddc;K)&-t7Y_sTwJM2S2y8ELSk*7T^66Gk`p#KC5?}I}Cz`?@ z(|o1yyAKH-55CH)M6zCXR~BWVvA{Lf5^Tp8jnz@(NK{iCv!1iFx=C~sbREc@e=3{A zR%2Y{F${-xR1rgvCFyA(>xQkhfVv^lP1Aq=1etWnI@!32uJL^)lZ8k-E*})&81O3a zk)0U73v{0$=(BV_@;b)0AKArKq&nD84E;-}6+RU#Xsf>=aaA2TbzBSzqt}~yBI$Ej z!rVzVV)Y;x-f@Mgn=nNh3Dk&npsc9y4}-(%&ZFbwQM3br?xI%#Us=n5`#`twWw!*1 zs7p)zJnC8SH?WBwbI%33WNq71*0T9VJ)Xkq9zq3v1#AU+Xf_|*0seD&8g(+APL6{2 if>E8GN0)yaEAS7aJVK+!9r$4Y0000P$ literal 0 HcmV?d00001 diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index dca7ce92a3..5a12f84abf 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -231,6 +231,14 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let dropInteraction = UIDropInteraction(delegate: self) self.navigationController?.navigationItem.leftBarButtonItems?.first?.customView?.addInteraction(dropInteraction) + + if(!UserDefaults.standard.bool(forKey: "isInitialPrivacySettingsShowed") || isApplicationUpdated()){ + redirectToPrivacyViewController() + + //set current app version + let appVersion = Bundle.main.infoDictionary?["CFBundleInfoDictionaryVersion"] as? String + UserDefaults.standard.set(appVersion, forKey: "CurrentAppVersion") + } NotificationCenter.default.addObserver(self, selector: #selector(changeTheming(_:)), name: NSNotification.Name(rawValue: global.notificationCenterChangeTheming), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource(_:)), name: NSNotification.Name(rawValue: global.notificationCenterReloadDataSource), object: nil) @@ -338,6 +346,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS dataSource.removeImageCache() } + + func isApplicationUpdated() -> Bool{ + let appVersion = Bundle.main.infoDictionary?["CFBundleInfoDictionaryVersion"] as? String ?? "" + let currentVersion = UserDefaults.standard.string(forKey: "CurrentAppVersion") + return currentVersion != appVersion + } + + func redirectToPrivacyViewController(){ + let storyBoard: UIStoryboard = UIStoryboard(name: "NCSettings", bundle: nil) + let newViewController = storyBoard.instantiateViewController(withIdentifier: "privacySettingsNavigation") as! UINavigationController + newViewController.modalPresentationStyle = .fullScreen + self.present(newViewController, animated: true, completion: nil) + } func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { let viewController = presentationController.presentedViewController diff --git a/iOSClient/Settings/AnalysisDataCollectionSwitch.swift b/iOSClient/Settings/AnalysisDataCollectionSwitch.swift new file mode 100644 index 0000000000..e24216220f --- /dev/null +++ b/iOSClient/Settings/AnalysisDataCollectionSwitch.swift @@ -0,0 +1,34 @@ +// +// AnalysisDataCollectionSwitch.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit + +class AnalysisDataCollectionSwitch: XLFormBaseCell { + + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var analysisDataCollectionSwitchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + analysisDataCollectionSwitchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + } + + @objc func switchChanged(mySwitch: UISwitch) { + self.rowDescriptor.value = mySwitch.isOn + } +} + diff --git a/iOSClient/Settings/AnalysisDataCollectionSwitch.xib b/iOSClient/Settings/AnalysisDataCollectionSwitch.xib new file mode 100644 index 0000000000..45530193f6 --- /dev/null +++ b/iOSClient/Settings/AnalysisDataCollectionSwitch.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/InitialPrivacySettingsViewController.swift b/iOSClient/Settings/InitialPrivacySettingsViewController.swift new file mode 100644 index 0000000000..2cd30a4242 --- /dev/null +++ b/iOSClient/Settings/InitialPrivacySettingsViewController.swift @@ -0,0 +1,170 @@ +// +// InitialPrivacySettingsViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import AppTrackingTransparency +import AdSupport +import UIKit + +class InitialPrivacySettingsViewController: UIViewController { + + @IBOutlet weak var dataPrivacyImage: UIImageView! + @IBOutlet weak var acceptButton: UIButton! + @IBOutlet weak var privacySettingsHelpText: UITextView! + @IBOutlet weak var privacySettingsTitle: UILabel! + @IBOutlet weak var widthPriavacyHelpView: NSLayoutConstraint! + var privacyHelpText = "" + + override func viewDidLoad() { + super.viewDidLoad() + + privacySettingsTitle.text = NSLocalizedString("_privacy_settings_title_", comment: "") + privacyHelpText = NSLocalizedString("_privacy_help_text_after_login_", comment: "") + privacySettingsHelpText.text = privacyHelpText + dataPrivacyImage.image = UIImage(named: "dataPrivacy")!.image(color: NCBrandColor.shared.brand, size: 60) + privacySettingsHelpText.delegate = self + privacySettingsHelpText.textColor = .label + privacySettingsHelpText.hyperLink(originalText: privacyHelpText, + linkTextsAndTypes: [NSLocalizedString("_key_privacy_help_", comment: ""): LinkType.privacyPolicy.rawValue, + NSLocalizedString("_key_reject_help_", comment: ""): LinkType.reject.rawValue, + NSLocalizedString("_key_settings_help_", comment: ""): LinkType.settings.rawValue]) + + acceptButton.backgroundColor = NCBrandColor.shared.brand + acceptButton.tintColor = UIColor.white + acceptButton.layer.cornerRadius = 5 + acceptButton.layer.borderWidth = 1 + acceptButton.layer.borderColor = NCBrandColor.shared.brand.cgColor + acceptButton.setTitle(NSLocalizedString("_accept_button_title_", comment: ""), for: .normal) + privacySettingsHelpText.centerText() + privacySettingsHelpText.font = UIFont(name: privacySettingsHelpText.font!.fontName, size: 16) + self.navigationItem.leftBarButtonItem?.tintColor = NCBrandColor.shared.brand + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.navigationController?.navigationBar.isHidden = true + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + self.navigationController?.navigationBar.isHidden = false + } + + override func viewDidLayoutSubviews(){ + if UIDevice.current.userInterfaceIdiom == .pad { + widthPriavacyHelpView.constant = UIScreen.main.bounds.width - 100 + } + } + + @IBAction func onAcceptButtonClicked(_ sender: Any) { + requestPermission() + } + + //NEWLY ADDED PERMISSIONS FOR iOS 14 + func requestPermission() { + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(true, forKey: "isAnalysisDataCollectionSwitchOn") + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization { status in + switch status { + case .authorized: + // Tracking authorization dialog was shown + // and we are authorized + print("Authorized") + // Now that we are authorized we can get the IDFA + print(ASIdentifierManager.shared().advertisingIdentifier) + case .denied: + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(false, forKey: "isAnalysisDataCollectionSwitchOn") + print("Denied") + case .notDetermined: + // Tracking authorization dialog has not been shown + print("Not Determined") + case .restricted: + print("Restricted") + @unknown default: + print("Unknown") + } + } + } else { + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + UserDefaults.standard.set(true, forKey: "isAnalysisDataCollectionSwitchOn") + } + self.dismiss(animated: true, completion: nil) + } +} +// MARK: - UITextViewDelegate +extension InitialPrivacySettingsViewController: UITextViewDelegate { + func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange) -> Bool { + if let linkType = LinkType(rawValue: URL.absoluteString) { + // TODO: handle linktype here with switch or similar. + switch linkType { + case LinkType.privacyPolicy: + //let storyBoard: UIStoryboard = UIStoryboard(name: "NCSettings", bundle: nil) + let privacyViewController = PrivacyPolicyViewController() + self.navigationController?.pushViewController(privacyViewController, animated: true) + case LinkType.reject: + UserDefaults.standard.set(false, forKey: "isAnalysisDataCollectionSwitchOn") + UserDefaults.standard.set(true, forKey: "isInitialPrivacySettingsShowed") + self.dismiss(animated: true, completion: nil) + case LinkType.settings: + let privacySettingsViewController = PrivacySettingsViewController() + UserDefaults.standard.set(true, forKey: "showSettingsButton") + self.navigationController?.pushViewController(privacySettingsViewController, animated: true) + } + print("handle link:: \(linkType)") + } + return false + } +} + +public extension UITextView { + + func hyperLink(originalText: String, linkTextsAndTypes: [String: String]) { + + let style = NSMutableParagraphStyle() + style.alignment = .left + + let attributedOriginalText = NSMutableAttributedString(string: originalText) + + let fullRange = NSRange(location: 0, length: attributedOriginalText.length) + attributedOriginalText.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.label, range: fullRange) + for linkTextAndType in linkTextsAndTypes { + let linkRange = attributedOriginalText.mutableString.range(of: linkTextAndType.key) + attributedOriginalText.addAttribute(NSAttributedString.Key.link, value: linkTextAndType.value, range: linkRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: fullRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.foregroundColor, value: NCBrandColor.shared.brand, range: linkRange) + attributedOriginalText.addAttribute(NSAttributedString.Key.font, value: UIFont.systemFont(ofSize: 10), range: fullRange) + } + + self.linkTextAttributes = [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.brand] + self.attributedText = attributedOriginalText + } + + func centerText() { + self.textAlignment = .justified + let fittingSize = CGSize(width: 300, height: CGFloat.greatestFiniteMagnitude) + let size = sizeThatFits(fittingSize) + let topOffset = (bounds.size.height - size.height * zoomScale) / 2 + let positiveTopOffset = max(1, topOffset) + contentOffset.y = -positiveTopOffset + } +} + +enum LinkType: String { + case reject + case privacyPolicy + case settings +} + + diff --git a/iOSClient/Settings/NCSettings.storyboard b/iOSClient/Settings/NCSettings.storyboard new file mode 100644 index 0000000000..19a320515b --- /dev/null +++ b/iOSClient/Settings/NCSettings.storyboard @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/PrivacyPolicyViewController.swift b/iOSClient/Settings/PrivacyPolicyViewController.swift new file mode 100644 index 0000000000..141c444fca --- /dev/null +++ b/iOSClient/Settings/PrivacyPolicyViewController.swift @@ -0,0 +1,62 @@ +// +// PrivacyPolicyViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import UIKit +import WebKit + +class PrivacyPolicyViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { + + var myWebView = WKWebView() + + override func viewDidLoad() { + super.viewDidLoad() + + self.title = NSLocalizedString("_privacy_policy_", comment: "") + + myWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + myWebView.uiDelegate = self + myWebView.navigationDelegate = self + myWebView.autoresizingMask = [.flexibleWidth, .flexibleHeight] + self.view.addSubview(myWebView) + + //1. Load web site into my web view + let myURL = URL(string: "https://static.magentacloud.de/privacy/datenschutzhinweise_app.htm") + let myURLRequest:URLRequest = URLRequest(url: myURL!) + NCActivityIndicator.shared.start() + myWebView.load(myURLRequest) + self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + myWebView = WKWebView(frame: CGRect(x:0, y:0, width: UIScreen.main.bounds.width, height:UIScreen.main.bounds.height)) + } + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { + NCActivityIndicator.shared.stop() + } + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { + if navigationAction.navigationType == .linkActivated { + if let url = navigationAction.request.url, + UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + decisionHandler(.cancel) + } else { + decisionHandler(.allow) + } + } else { + decisionHandler(.allow) + } + } +} diff --git a/iOSClient/Settings/PrivacySettingsViewController.swift b/iOSClient/Settings/PrivacySettingsViewController.swift new file mode 100644 index 0000000000..3e60dd6212 --- /dev/null +++ b/iOSClient/Settings/PrivacySettingsViewController.swift @@ -0,0 +1,133 @@ +// +// PrivacySettingsViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import AppTrackingTransparency +import AdSupport + +class PrivacySettingsViewController: XLFormViewController{ + + @objc public var isShowSettingsButton: Bool = false + + override func viewDidLoad() { + super.viewDidLoad() + self.title = NSLocalizedString("_privacy_settings_title_", comment: "") + + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) + + let nib = UINib(nibName: "CustomSectionHeader", bundle: nil) + self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "customSectionHeader") + isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") + self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand + changeTheming() + } + + @objc func changeTheming() { + tableView.backgroundColor = .systemGroupedBackground + tableView.separatorColor = .none + tableView.separatorColor = .clear + tableView.reloadData() + initializeForm() + } + + //MARK: XLForm + func initializeForm() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = " " + form.addFormSection(section) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_privacy_settings_help_text_", comment: "") + form.addFormSection(section) + + //custom cell + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["RequiredDataCollectionCustomCellType"] = RequiredDataCollectionSwitch.self + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") + row.cellConfig["requiredDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_required_data_collection_", comment: "") + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["AnalysisDataCollectionCustomCellType"] = AnalysisDataCollectionSwitch.self + + row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") + row.cellConfig["analysisDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_analysis_data_acqusition_", comment: "") + if(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn")){ + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 1 + }else { + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 0 + } + + section.addFormRow(row) + + XLFormViewController.cellClassesForRowDescriptorTypes()["SaveSettingsButton"] = SaveSettingsCustomButtonCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: "") + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: "SaveSettingsButton", rowType: "SaveSettingsButton", title: "") + row.cellConfig["backgroundColor"] = UIColor.clear + + if(isShowSettingsButton){ + section.addFormRow(row) + } + + self.form = form + } + + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + + if formRow.tag == "SaveSettingsButton" { + print("save settings clicked") + //TODO save button state and leave the page + self.navigationController?.popViewController(animated: true) + + } + if formRow.tag == "AnalysisDataCollectionSwitch"{ + if (formRow.value! as AnyObject).boolValue { + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization(completionHandler: { (status) in + if status == .denied { + guard let url = URL(string: UIApplication.openSettingsURLString) else { + return + } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:]) + } + } + }) + } + } + UserDefaults.standard.set((formRow.value! as AnyObject).boolValue, forKey: "isAnalysisDataCollectionSwitchOn") + } + } +} diff --git a/iOSClient/Settings/RequiredDataCollectionSwitch.swift b/iOSClient/Settings/RequiredDataCollectionSwitch.swift new file mode 100644 index 0000000000..f80aa97e89 --- /dev/null +++ b/iOSClient/Settings/RequiredDataCollectionSwitch.swift @@ -0,0 +1,34 @@ +// +// RequiredDataCollectionSwitch.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit + + +class RequiredDataCollectionSwitch: XLFormBaseCell { + + @IBOutlet weak var cellLabel: UILabel! + @IBOutlet weak var requiredDataCollectionSwitchControl: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + //requiredDataCollectionSwitchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged) + + } + + override func configure() { + super.configure() + + requiredDataCollectionSwitchControl.isOn = true + requiredDataCollectionSwitchControl.isEnabled = false + } + + override func update() { + super.update() + } +} diff --git a/iOSClient/Settings/RequiredDataCollectionSwitch.xib b/iOSClient/Settings/RequiredDataCollectionSwitch.xib new file mode 100644 index 0000000000..66156c6e06 --- /dev/null +++ b/iOSClient/Settings/RequiredDataCollectionSwitch.xib @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Settings/SaveSettingsCustomButtonCell.swift b/iOSClient/Settings/SaveSettingsCustomButtonCell.swift new file mode 100644 index 0000000000..6205727723 --- /dev/null +++ b/iOSClient/Settings/SaveSettingsCustomButtonCell.swift @@ -0,0 +1,46 @@ +// +// SaveSettingsCustomButtonCell.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import UIKit + + +class SaveSettingsCustomButtonCell: XLFormButtonCell { + + @IBOutlet weak var saveSettingsButton: UIButton! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + self.selectionStyle = .none + self.separatorInset = UIEdgeInsets(top: 0, left: .greatestFiniteMagnitude, bottom: 0, right: .greatestFiniteMagnitude) + saveSettingsButton.setTitle(NSLocalizedString("_save_settings_", comment: ""), for: .normal) + saveSettingsButton.addTarget(self, action: #selector(saveButtonClicked), for: .touchUpInside) + + } + + override func configure() { + super.configure() + saveSettingsButton.backgroundColor = NCBrandColor.shared.brand + saveSettingsButton.tintColor = UIColor.white + saveSettingsButton.layer.cornerRadius = 5 + saveSettingsButton.layer.borderWidth = 1 + saveSettingsButton.layer.borderColor = NCBrandColor.shared.brand.cgColor + + } + + override func update() { + super.update() + + } + + @objc func saveButtonClicked(sender: UIButton) { + self.rowDescriptor.value = sender + + } + +} diff --git a/iOSClient/Settings/SaveSettingsCustomButtonCell.xib b/iOSClient/Settings/SaveSettingsCustomButtonCell.xib new file mode 100644 index 0000000000..0dd197da31 --- /dev/null +++ b/iOSClient/Settings/SaveSettingsCustomButtonCell.xib @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From c282d0e9d82d560f9b2f13c635efec47721d05fd Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Wed, 18 Oct 2023 14:58:46 +0530 Subject: [PATCH 2/5] NMC 1984 - Unit test added for privacy policy view controller --- .../PrivacyPolicyTest.swift | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 Tests/NextcloudUnitTests/PrivacyPolicyTest.swift diff --git a/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift b/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift new file mode 100644 index 0000000000..f6265f48e7 --- /dev/null +++ b/Tests/NextcloudUnitTests/PrivacyPolicyTest.swift @@ -0,0 +1,154 @@ +// +// PrivacyPolicyTest.swift +// NextcloudTests +// +// Created by A200073704 on 27/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +@testable import Nextcloud +import XCTest +import NextcloudKit +import XLForm + + + class PrivacyPolicyTest: XCTestCase { + + var viewController: InitialPrivacySettingsViewController? + var privacySettingsView = PrivacySettingsViewController() + + override func setUpWithError() throws { + + // To Create an instance of UIStoryboard + let storyboard = UIStoryboard(name: "NCSettings", bundle: nil) + + // To Instantiate UIViewController with Storyboard ID + viewController = storyboard.instantiateViewController(withIdentifier: "privacyPolicyViewController") as? InitialPrivacySettingsViewController + + // Outlets are connected + let _ = viewController?.view + + // Make the viewDidLoad() execute. + viewController?.loadViewIfNeeded() + + } + + override func tearDownWithError() throws { + viewController = nil + } + + func testPrivacyPolicyViewControllerIsOpen() { + + // Check that the InitialPrivacyPolicyViewController gets opened + let storyboard = UIStoryboard(name: "NCSettings", bundle: nil) + if let privacyPolicyViewController = storyboard.instantiateViewController(withIdentifier: "privacyPolicyViewController") as? InitialPrivacySettingsViewController { + let navigationController = UINavigationController(rootViewController: privacyPolicyViewController) + + privacyPolicyViewController.loadViewIfNeeded() + + XCTAssertTrue(navigationController.topViewController is InitialPrivacySettingsViewController, "Privacy policy view controller should be open") + } + } + + func testTextViewHasCorrectText() { + + //Check that the text displayed is correct + let expectedText = NSLocalizedString("_privacy_help_text_after_login_", comment: "") + viewController?.privacySettingsHelpText?.text = expectedText + + let actualText = viewController?.privacySettingsHelpText?.text + XCTAssertEqual(actualText, expectedText, "The text view does not have the expected text") + } + + func testHasAcceptButton() { + + // Check that view has the accept button + let acceptButton = viewController?.acceptButton + + XCTAssertNotNil(acceptButton, "View controller does not have an accept button") + + } + + func testSettingsLinkTypeNavigatesToPrivacySettingsViewController() { + + // Simulate tapping the "Settings" link type + let linkType = LinkType.settings + + UserDefaults.standard.set(true, forKey: "showSettingsButton") + viewController?.privacySettingsHelpText.hyperLink(originalText: viewController?.privacyHelpText ?? "", linkTextsAndTypes: [NSLocalizedString("_key_settings_help_", comment: ""): linkType.rawValue]) + + // Check that the correct view controller was pushed onto the navigation stack + XCTAssertNotNil(viewController?.navigationController?.visibleViewController is PrivacySettingsViewController) + } + + func testPrivacyPolicyLinkType_NavigatesToPrivacyPolicyViewController() { + + // Simulate tapping the "Privacy Policy" link type + let linkType = LinkType.privacyPolicy + + viewController?.privacySettingsHelpText.hyperLink(originalText: viewController?.privacyHelpText ?? "", linkTextsAndTypes: [NSLocalizedString("_key_privacy_help_", comment: ""): linkType.rawValue]) + + // Check that the correct view controller was pushed onto the navigation + XCTAssertNotNil(viewController?.navigationController?.visibleViewController is PrivacyPolicyViewController) + } + + func testCorrectImagePresentOnInitialPrivacySettingsViewController() { + + // Check that the image view has the correct image + let expectedImage = UIImage(named: "dataPrivacy") + XCTAssertNotNil(expectedImage) + } + + func testAcceptButtonHasBackgroundColor() { + + // Check that the accept button has the correct background color + let expectedColor = NCBrandColor.shared.brand + XCTAssertEqual(viewController?.acceptButton.backgroundColor, expectedColor) + + } + + func testShowSaveSettingsButton() { + + privacySettingsView.isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") + + XCTAssertTrue(privacySettingsView.isShowSettingsButton) + + } + + func testRequiredDataCollectionSectionExists() { + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // the section with the title "Required Data Collection" + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") + + // Verify that section was found + XCTAssertNotNil(row, "Expected 'Required Data Collection' section to exist in form.") + } + + func testAnalysisDataCollectionSection() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // row with tag "AnalysisDataCollectionSwitch" + row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") + + // Assert that the row exists + XCTAssertNotNil(row, "Expected row with tag 'AnalysisDataCollectionSwitch' to exist in form.") + + // Verify the switch is off + XCTAssertFalse(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn"), "Expected isAnalysisDataCollectionSwitchOn to be false.") + } + + +} From 9fde106ea30556828ebb502e1d7eb14c6b65285c Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:01:04 +0530 Subject: [PATCH 3/5] NMC 1984 - privacySettingsViewController file removed to avoid conflicts --- .../PrivacySettingsViewController.swift | 133 ------------------ 1 file changed, 133 deletions(-) diff --git a/iOSClient/Settings/PrivacySettingsViewController.swift b/iOSClient/Settings/PrivacySettingsViewController.swift index 3e60dd6212..e69de29bb2 100644 --- a/iOSClient/Settings/PrivacySettingsViewController.swift +++ b/iOSClient/Settings/PrivacySettingsViewController.swift @@ -1,133 +0,0 @@ -// -// PrivacySettingsViewController.swift -// Nextcloud -// -// Created by A200073704 on 25/04/23. -// Copyright © 2023 Marino Faggiana. All rights reserved. -// - -import Foundation -import AppTrackingTransparency -import AdSupport - -class PrivacySettingsViewController: XLFormViewController{ - - @objc public var isShowSettingsButton: Bool = false - - override func viewDidLoad() { - super.viewDidLoad() - self.title = NSLocalizedString("_privacy_settings_title_", comment: "") - - NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) - - let nib = UINib(nibName: "CustomSectionHeader", bundle: nil) - self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "customSectionHeader") - isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") - self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand - changeTheming() - } - - @objc func changeTheming() { - tableView.backgroundColor = .systemGroupedBackground - tableView.separatorColor = .none - tableView.separatorColor = .clear - tableView.reloadData() - initializeForm() - } - - //MARK: XLForm - func initializeForm() { - let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor - form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow - - var section : XLFormSectionDescriptor - var row : XLFormRowDescriptor - - // Section: Destination Folder - - section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) - section.footerTitle = " " - form.addFormSection(section) - - section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) - section.footerTitle = NSLocalizedString("_privacy_settings_help_text_", comment: "") - form.addFormSection(section) - - //custom cell - section = XLFormSectionDescriptor.formSection(withTitle: "") - section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") - form.addFormSection(section) - - XLFormViewController.cellClassesForRowDescriptorTypes()["RequiredDataCollectionCustomCellType"] = RequiredDataCollectionSwitch.self - - row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") - row.cellConfig["requiredDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand - row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue - row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["cellLabel.textColor"] = UIColor.label //photos - row.cellConfig["cellLabel.text"] = NSLocalizedString("_required_data_collection_", comment: "") - section.addFormRow(row) - - section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) - section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") - form.addFormSection(section) - - XLFormViewController.cellClassesForRowDescriptorTypes()["AnalysisDataCollectionCustomCellType"] = AnalysisDataCollectionSwitch.self - - row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") - row.cellConfig["analysisDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand - row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue - row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) - row.cellConfig["cellLabel.textColor"] = UIColor.label //photos - row.cellConfig["cellLabel.text"] = NSLocalizedString("_analysis_data_acqusition_", comment: "") - if(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn")){ - row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 1 - }else { - row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 0 - } - - section.addFormRow(row) - - XLFormViewController.cellClassesForRowDescriptorTypes()["SaveSettingsButton"] = SaveSettingsCustomButtonCell.self - - section = XLFormSectionDescriptor.formSection(withTitle: "") - form.addFormSection(section) - - row = XLFormRowDescriptor(tag: "SaveSettingsButton", rowType: "SaveSettingsButton", title: "") - row.cellConfig["backgroundColor"] = UIColor.clear - - if(isShowSettingsButton){ - section.addFormRow(row) - } - - self.form = form - } - - override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { - super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) - - if formRow.tag == "SaveSettingsButton" { - print("save settings clicked") - //TODO save button state and leave the page - self.navigationController?.popViewController(animated: true) - - } - if formRow.tag == "AnalysisDataCollectionSwitch"{ - if (formRow.value! as AnyObject).boolValue { - if #available(iOS 14, *) { - ATTrackingManager.requestTrackingAuthorization(completionHandler: { (status) in - if status == .denied { - guard let url = URL(string: UIApplication.openSettingsURLString) else { - return - } - if UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:]) - } - } - }) - } - } - UserDefaults.standard.set((formRow.value! as AnyObject).boolValue, forKey: "isAnalysisDataCollectionSwitchOn") - } - } -} From 86439cfb9b142ac0184473bdec1cb0b9b24351b9 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Tue, 26 Dec 2023 13:29:37 +0530 Subject: [PATCH 4/5] NMC 1984 - Privacy setting view controller added --- .../PrivacySettingsViewController.swift | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/iOSClient/Settings/PrivacySettingsViewController.swift b/iOSClient/Settings/PrivacySettingsViewController.swift index e69de29bb2..b7883ad800 100644 --- a/iOSClient/Settings/PrivacySettingsViewController.swift +++ b/iOSClient/Settings/PrivacySettingsViewController.swift @@ -0,0 +1,147 @@ +// +// PrivacySettingsViewController.swift +// Nextcloud +// +// Created by A200073704 on 25/04/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import Foundation +import AppTrackingTransparency +import AdSupport + +class PrivacySettingsViewController: XLFormViewController{ + + @objc public var isShowSettingsButton: Bool = false + + override func viewDidLoad() { + super.viewDidLoad() + self.title = NSLocalizedString("_privacy_settings_title_", comment: "") + + NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil) + + let nib = UINib(nibName: "CustomSectionHeader", bundle: nil) + self.tableView.register(nib, forHeaderFooterViewReuseIdentifier: "customSectionHeader") + isShowSettingsButton = UserDefaults.standard.bool(forKey: "showSettingsButton") + self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.brand + changeTheming() + } + + @objc func changeTheming() { + tableView.backgroundColor = .systemGroupedBackground + tableView.separatorColor = .none + tableView.separatorColor = .clear + tableView.reloadData() + initializeForm() + } + + + + //MARK: XLForm + + func initializeForm() { + + let form : XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section : XLFormSectionDescriptor + var row : XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = " " + form.addFormSection(section) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_privacy_settings_help_text_", comment: "") + form.addFormSection(section) + + + //custom cell + section = XLFormSectionDescriptor.formSection(withTitle: "") + section.footerTitle = NSLocalizedString("_required_data_collection_help_text_", comment: "") + form.addFormSection(section) + + + XLFormViewController.cellClassesForRowDescriptorTypes()["RequiredDataCollectionCustomCellType"] = RequiredDataCollectionSwitch.self + + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "RequiredDataCollectionCustomCellType", title: "") + row.cellConfig["requiredDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_required_data_collection_", comment: "") + section.addFormRow(row) + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("", comment: "").uppercased()) + section.footerTitle = NSLocalizedString("_analysis_data_acqusition_help_text_", comment: "") + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["AnalysisDataCollectionCustomCellType"] = AnalysisDataCollectionSwitch.self + + + row = XLFormRowDescriptor(tag: "AnalysisDataCollectionSwitch", rowType: "AnalysisDataCollectionCustomCellType", title: "") + row.cellConfig["analysisDataCollectionSwitchControl.onTintColor"] = NCBrandColor.shared.brand + row.cellConfig["cellLabel.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["cellLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["cellLabel.textColor"] = UIColor.label //photos + row.cellConfig["cellLabel.text"] = NSLocalizedString("_analysis_data_acqusition_", comment: "") + if(UserDefaults.standard.bool(forKey: "isAnalysisDataCollectionSwitchOn")){ + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 1 + }else { + row.cellConfigAtConfigure["analysisDataCollectionSwitchControl.on"] = 0 + } + + section.addFormRow(row) + + + XLFormViewController.cellClassesForRowDescriptorTypes()["SaveSettingsButton"] = SaveSettingsCustomButtonCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: "") + form.addFormSection(section) + + + row = XLFormRowDescriptor(tag: "SaveSettingsButton", rowType: "SaveSettingsButton", title: "") + row.cellConfig["backgroundColor"] = UIColor.clear + + if(isShowSettingsButton){ + section.addFormRow(row) + } + + + self.form = form + } + + + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + + if formRow.tag == "SaveSettingsButton" { + print("save settings clicked") + //TODO save button state and leave the page + self.navigationController?.popViewController(animated: true) + + } + if formRow.tag == "AnalysisDataCollectionSwitch"{ + if (formRow.value! as AnyObject).boolValue { + if #available(iOS 14, *) { + ATTrackingManager.requestTrackingAuthorization(completionHandler: { (status) in + if status == .denied { + guard let url = URL(string: UIApplication.openSettingsURLString) else { + return + } + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url, options: [:]) + } + } + }) + } + } + UserDefaults.standard.set((formRow.value! as AnyObject).boolValue, forKey: "isAnalysisDataCollectionSwitchOn") + } + + } + +} From 8d2d887b5bcbfd7955b0b4834efe6aa2a373107a Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Wed, 9 Apr 2025 14:10:39 +0530 Subject: [PATCH 5/5] NMC 1984 - Privacy policy customisation changes added --- Nextcloud.xcodeproj/project.pbxproj | 47 +++ ...mon+CollectionViewDelegateFlowLayout.swift | 43 +++ .../NCCollectionViewCommon.swift | 360 ++++++++++++++---- 3 files changed, 383 insertions(+), 67 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index ee34afa1ec..92f5bc2923 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -92,6 +92,19 @@ AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; }; AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* Shareable.swift */; }; + AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; }; + B54315362DA64EB100981E7E /* PrivacyPolicyTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315352DA64EB100981E7E /* PrivacyPolicyTest.swift */; }; + B54315412DA669C700981E7E /* InitialPrivacySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315392DA669C700981E7E /* InitialPrivacySettingsViewController.swift */; }; + B54315422DA669C700981E7E /* RequiredDataCollectionSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543153D2DA669C700981E7E /* RequiredDataCollectionSwitch.swift */; }; + B54315432DA669C700981E7E /* PrivacySettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543153C2DA669C700981E7E /* PrivacySettingsViewController.swift */; }; + B54315442DA669C700981E7E /* AnalysisDataCollectionSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315372DA669C700981E7E /* AnalysisDataCollectionSwitch.swift */; }; + B54315452DA669C700981E7E /* PrivacyPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543153B2DA669C700981E7E /* PrivacyPolicyViewController.swift */; }; + B54315462DA669C700981E7E /* SaveSettingsCustomButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543153F2DA669C700981E7E /* SaveSettingsCustomButtonCell.swift */; }; + B54315472DA669C700981E7E /* AnalysisDataCollectionSwitch.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54315382DA669C700981E7E /* AnalysisDataCollectionSwitch.xib */; }; + B54315482DA669C700981E7E /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B543153A2DA669C700981E7E /* NCSettings.storyboard */; }; + B54315492DA669C700981E7E /* SaveSettingsCustomButtonCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54315402DA669C700981E7E /* SaveSettingsCustomButtonCell.xib */; }; + B543154A2DA669C700981E7E /* RequiredDataCollectionSwitch.xib in Resources */ = {isa = PBXBuildFile; fileRef = B543153E2DA669C700981E7E /* RequiredDataCollectionSwitch.xib */; }; + C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */; }; D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; }; @@ -1319,6 +1332,18 @@ AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = ""; }; AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = ""; }; AFCE353827E5DE0400FEA6C2 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; }; + AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; }; + B54315352DA64EB100981E7E /* PrivacyPolicyTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyTest.swift; sourceTree = ""; }; + B54315372DA669C700981E7E /* AnalysisDataCollectionSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalysisDataCollectionSwitch.swift; sourceTree = ""; }; + B54315382DA669C700981E7E /* AnalysisDataCollectionSwitch.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AnalysisDataCollectionSwitch.xib; sourceTree = ""; }; + B54315392DA669C700981E7E /* InitialPrivacySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitialPrivacySettingsViewController.swift; sourceTree = ""; }; + B543153A2DA669C700981E7E /* NCSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCSettings.storyboard; sourceTree = ""; }; + B543153B2DA669C700981E7E /* PrivacyPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyPolicyViewController.swift; sourceTree = ""; }; + B543153C2DA669C700981E7E /* PrivacySettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySettingsViewController.swift; sourceTree = ""; }; + B543153D2DA669C700981E7E /* RequiredDataCollectionSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequiredDataCollectionSwitch.swift; sourceTree = ""; }; + B543153E2DA669C700981E7E /* RequiredDataCollectionSwitch.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RequiredDataCollectionSwitch.xib; sourceTree = ""; }; + B543153F2DA669C700981E7E /* SaveSettingsCustomButtonCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveSettingsCustomButtonCell.swift; sourceTree = ""; }; + B54315402DA669C700981E7E /* SaveSettingsCustomButtonCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SaveSettingsCustomButtonCell.xib; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -2096,6 +2121,8 @@ isa = PBXGroup; children = ( AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B54315352DA64EB100981E7E /* PrivacyPolicyTest.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -2559,6 +2586,16 @@ F76882042C0DD1E7001CF441 /* Settings */ = { isa = PBXGroup; children = ( + B54315372DA669C700981E7E /* AnalysisDataCollectionSwitch.swift */, + B54315382DA669C700981E7E /* AnalysisDataCollectionSwitch.xib */, + B54315392DA669C700981E7E /* InitialPrivacySettingsViewController.swift */, + B543153A2DA669C700981E7E /* NCSettings.storyboard */, + B543153B2DA669C700981E7E /* PrivacyPolicyViewController.swift */, + B543153C2DA669C700981E7E /* PrivacySettingsViewController.swift */, + B543153D2DA669C700981E7E /* RequiredDataCollectionSwitch.swift */, + B543153E2DA669C700981E7E /* RequiredDataCollectionSwitch.xib */, + B543153F2DA669C700981E7E /* SaveSettingsCustomButtonCell.swift */, + B54315402DA669C700981E7E /* SaveSettingsCustomButtonCell.xib */, F768820B2C0DD1E7001CF441 /* Settings */, F76882162C0DD1E7001CF441 /* AutoUpload */, F768821C2C0DD1E7001CF441 /* Display */, @@ -3943,6 +3980,10 @@ 3704EB2A23D5A58400455C5B /* NCMenu.storyboard in Resources */, AF93471C27E2361E002537EE /* NCShareHeader.xib in Resources */, F75D901F2D2BE12E003E740B /* NCRecommendationsCell.xib in Resources */, + B54315472DA669C700981E7E /* AnalysisDataCollectionSwitch.xib in Resources */, + B54315482DA669C700981E7E /* NCSettings.storyboard in Resources */, + B54315492DA669C700981E7E /* SaveSettingsCustomButtonCell.xib in Resources */, + B543154A2DA669C700981E7E /* RequiredDataCollectionSwitch.xib in Resources */, F76032A0252F0F8E0015A421 /* NCTransferCell.xib in Resources */, F7F4F10527ECDBDB008676F9 /* Inconsolata-SemiBold.ttf in Resources */, F7A48415297028FC00BD1B49 /* Nextcloud Hub.png in Resources */, @@ -4578,6 +4619,12 @@ F72408332B8A27C900F128E2 /* NCMedia+Command.swift in Sources */, F755CB402B8CB13C00CE27E9 /* NCMediaLayout.swift in Sources */, F73EF7B72B0224AB0087E6E9 /* NCManageDatabase+ExternalSites.swift in Sources */, + B54315412DA669C700981E7E /* InitialPrivacySettingsViewController.swift in Sources */, + B54315422DA669C700981E7E /* RequiredDataCollectionSwitch.swift in Sources */, + B54315432DA669C700981E7E /* PrivacySettingsViewController.swift in Sources */, + B54315442DA669C700981E7E /* AnalysisDataCollectionSwitch.swift in Sources */, + B54315452DA669C700981E7E /* PrivacyPolicyViewController.swift in Sources */, + B54315462DA669C700981E7E /* SaveSettingsCustomButtonCell.swift in Sources */, AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */, F73EF7E72B0226B90087E6E9 /* NCManageDatabase+UserStatus.swift in Sources */, F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */, diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift index 76258bdfc9..ae785ea533 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegateFlowLayout.swift @@ -32,4 +32,47 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return sizeForFooterInSection(section: section) } + + func getHeaderHeight() -> CGFloat { + + var size: CGFloat = 0 + // transfer in progress + if headerMenuTransferView, + let metadata = NCManageDatabase.shared.getMetadataFromOcId(NCNetworking.shared.transferInForegorund?.ocId), + metadata.isTransferInForeground { + if !isSearchingMode { + size += NCGlobal.shared.heightHeaderTransfer + } + } else { + NCNetworking.shared.transferInForegorund = nil + } + + if headerMenuButtonsView { + size += NCGlobal.shared.heightButtonsView + } + + return size + } + + func getHeaderHeight(section: Int) -> (heightHeaderCommands: CGFloat, heightHeaderRichWorkspace: CGFloat, heightHeaderSection: CGFloat) { + + var headerRichWorkspace: CGFloat = 0 + + if let richWorkspaceText = richWorkspaceText, showDescription { + let trimmed = richWorkspaceText.trimmingCharacters(in: .whitespaces) + if !trimmed.isEmpty && !isSearchingMode { + headerRichWorkspace = UIScreen.main.bounds.size.height / 6 + } + } + + if isSearchingMode || layoutForView?.layout == NCGlobal.shared.layoutGrid || dataSource.numberOfSections() > 1 { + if section == 0 { + return (getHeaderHeight(), headerRichWorkspace, NCGlobal.shared.heightSection) + } else { + return (0, 0, NCGlobal.shared.heightSection) + } + } else { + return (getHeaderHeight(), headerRichWorkspace, 0) + } + } } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 5a12f84abf..3068db82aa 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -27,7 +27,7 @@ import RealmSwift import NextcloudKit import EasyTipView -class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCPhotoCellDelegate, NCSectionFirstHeaderDelegate, NCSectionFooterDelegate, NCSectionFirstHeaderEmptyDataDelegate, NCAccountSettingsModelDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate { +class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCPhotoCellDelegate, NCSectionHeaderMenuDelegate, NCSectionFooterDelegate, NCSectionFirstHeaderEmptyDataDelegate, NCAccountSettingsModelDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate, NCEmptyDataSetDelegate { @IBOutlet weak var collectionView: UICollectionView! @@ -73,10 +73,17 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var titleCurrentFolder = "" var titlePreviusFolder: String? var enableSearchBar: Bool = false + let maxImageGrid: CGFloat = 7 + var headerMenu: NCSectionHeaderMenu? + var headerMenuTransferView = false + var headerMenuButtonsView: Bool = true var headerRichWorkspaceDisable: Bool = false + + var groupByField = "name" var emptyImageName: String? var emptyImageColors: [UIColor]? + var emptyImage: UIImage? var emptyTitle: String = "" var emptyDescription: String = "" @@ -95,6 +102,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var numberOfColumns: Int = 0 var lastNumberOfColumns: Int = 0 + var isTransitioning: Bool = false + var selectableDataSource: [RealmSwiftObject] { dataSource.getMetadataSourceForAllSections() } + var pushed: Bool = false + var emptyDataSet: NCEmptyDataSet? + let heightHeaderRecommendations: CGFloat = 160 let heightHeaderSection: CGFloat = 30 @@ -173,8 +185,11 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS view.backgroundColor = .systemBackground collectionView.backgroundColor = .systemBackground - refreshControl.tintColor = NCBrandColor.shared.textColor2 - + refreshControl.tintColor = .gray + + listLayout = NCListLayout() + gridLayout = NCGridLayout() + if enableSearchBar { searchController = UISearchController(searchResultsController: nil) searchController?.searchResultsUpdater = self @@ -183,7 +198,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS searchController?.searchBar.delegate = self searchController?.searchBar.autocapitalizationType = .none navigationItem.searchController = searchController - navigationItem.hidesSearchBarWhenScrolling = true + navigationItem.hidesSearchBarWhenScrolling = false + navigationItem.backBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_back_", comment: ""), style: .plain, target: nil, action: nil) } // Cell @@ -193,12 +209,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS collectionView.register(UINib(nibName: "NCTransferCell", bundle: nil), forCellWithReuseIdentifier: "transferCell") // Header - collectionView.register(UINib(nibName: "NCSectionFirstHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeader") - collectionView.register(UINib(nibName: "NCSectionFirstHeader", bundle: nil), forSupplementaryViewOfKind: mediaSectionHeader, withReuseIdentifier: "sectionFirstHeader") + collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") collectionView.register(UINib(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeader") - collectionView.register(UINib(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: mediaSectionHeader, withReuseIdentifier: "sectionHeader") - collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") - collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: mediaSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") // Footer collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") @@ -214,6 +226,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } } + + // Empty + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: getHeaderHeight(), delegate: self) let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressCollecationView(_:))) longPressedGesture.minimumPressDuration = 0.5 @@ -257,13 +272,20 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS navigationController?.navigationBar.topItem?.title = titlePreviusFolder } navigationItem.title = titleCurrentFolder + navigationController?.setNavigationBarAppearance() + navigationController?.navigationBar.prefersLargeTitles = true + navigationController?.setNavigationBarHidden(false, animated: true) + + appDelegate.activeViewController = self isEditMode = false - (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems() - (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() + /// Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() + setNavigationRightItems() layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) + gridLayout.column = CGFloat(layoutForView?.columnGrid ?? 3) if isLayoutList { collectionView?.collectionViewLayout = listLayout self.layoutType = global.layoutList @@ -303,8 +325,13 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NotificationCenter.default.addObserver(self, selector: #selector(uploadedFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadedFile), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(uploadedLivePhoto(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadedLivePhoto), object: nil) NotificationCenter.default.addObserver(self, selector: #selector(uploadCancelFile(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUploadCancelFile), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(updateShare(_:)), name: NSNotification.Name(rawValue: global.notificationCenterUpdateShare), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: global.notificationCenterProgressTask), object: nil) + + // FIXME: iPAD PDF landscape mode iOS 16 + DispatchQueue.main.async { + self.collectionView?.collectionViewLayout.invalidateLayout() + } } override func viewWillDisappear(_ animated: Bool) { @@ -312,7 +339,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NCNetworking.shared.cancelUnifiedSearchFiles() dismissTip() - + pushed = false + toggleSelect(isOn: false) // Cancel Queue & Retrieves Properties NCNetworking.shared.downloadThumbnailQueue.cancelAll() NCNetworking.shared.unifiedSearchQueue.cancelAll() @@ -329,6 +357,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterDeleteFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCopyMoveFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCopyFile), object: nil) + NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterMoveFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterRenameFile), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterCreateFolder), object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: global.notificationCenterFavoriteFile), object: nil) @@ -347,13 +377,13 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS dataSource.removeImageCache() } - func isApplicationUpdated() -> Bool{ + func isApplicationUpdated() -> Bool { let appVersion = Bundle.main.infoDictionary?["CFBundleInfoDictionaryVersion"] as? String ?? "" let currentVersion = UserDefaults.standard.string(forKey: "CurrentAppVersion") return currentVersion != appVersion } - func redirectToPrivacyViewController(){ + func redirectToPrivacyViewController() { let storyBoard: UIStoryboard = UIStoryboard(name: "NCSettings", bundle: nil) let newViewController = storyBoard.instantiateViewController(withIdentifier: "privacySettingsNavigation") as! UINavigationController newViewController.modalPresentationStyle = .fullScreen @@ -437,7 +467,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.collectionView.collectionViewLayout.invalidateLayout() - (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() +// (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() } @objc func reloadDataSource(_ notification: NSNotification) { @@ -551,6 +581,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS NCContentPresenter().showError(error: error) } reloadDataSource() + } else { + collectionView.reloadData() } } @@ -638,7 +670,25 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } @objc func uploadStartFile(_ notification: NSNotification) { - collectionView?.reloadData() + guard let userInfo = notification.userInfo as NSDictionary?, + let ocId = userInfo["ocId"] as? String, + let serverUrl = userInfo["serverUrl"] as? String, + let account = userInfo["account"] as? String, + !isSearchingMode, + let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) + else { return } + + // Header view trasfer + if metadata.isTransferInForeground { + NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: 0) + DispatchQueue.main.async { self.collectionView?.reloadData() } + } + + if account == self.session.account, serverUrl == self.serverUrl { + reloadDataSource() + } else { + collectionView?.reloadData() + } } @objc func uploadedFile(_ notification: NSNotification) { @@ -689,8 +739,78 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } + @objc func triggerProgressTask(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let progressNumber = userInfo["progress"] as? NSNumber, + let totalBytes = userInfo["totalBytes"] as? Int64, + let totalBytesExpected = userInfo["totalBytesExpected"] as? Int64, + let ocId = userInfo["ocId"] as? String, + let ocIdTransfer = userInfo["ocIdTransfer"] as? String, + let session = userInfo["session"] as? String + else { return } + + let chunk: Int = userInfo["chunk"] as? Int ?? 0 + let e2eEncrypted: Bool = userInfo["e2eEncrypted"] as? Bool ?? false + + let transfer = NCTransferProgress.shared.append(NCTransferProgress.Transfer(ocId: ocId, ocIdTransfer: ocIdTransfer, session: session, chunk: chunk, e2eEncrypted: e2eEncrypted, progressNumber: progressNumber, totalBytes: totalBytes, totalBytesExpected: totalBytesExpected)) + + // HEADER +// if self.headerMenuTransferView, transfer.session.contains("upload") { +// self.sectionFirstHeader?.setViewTransfer(isHidden: false, progress: transfer.progressNumber.floatValue) +// self.sectionFirstHeaderEmptyData?.setViewTransfer(isHidden: false, progress: transfer.progressNumber.floatValue) +// } + + DispatchQueue.main.async { + if self.headerMenuTransferView && (chunk > 0 || e2eEncrypted) { + if NCNetworking.shared.transferInForegorund?.ocId == ocId { + NCNetworking.shared.transferInForegorund?.progress = progressNumber.floatValue + } else { + NCNetworking.shared.transferInForegorund = NCNetworking.TransferInForegorund(ocId: ocId, progress: progressNumber.floatValue) + self.collectionView.reloadData() + } + self.headerMenu?.progressTransfer.progress = transfer.progressNumber.floatValue + } else { + guard let indexPath = self.dataSource.getIndexPathMetadata(ocId: ocId).indexPath, + let cell = self.collectionView?.cellForItem(at: indexPath), + let cell = cell as? NCCellProtocol else { return } + if progressNumber.floatValue == 1 && !(cell is NCTransferCell) { + cell.fileProgressView?.isHidden = true + cell.fileProgressView?.progress = .zero + cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.images.buttonMore) + if let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { + cell.writeInfoDateSize(date: metadata.date, size: metadata.size) + } else { + cell.fileInfoLabel?.text = "" + cell.fileSubinfoLabel?.text = "" + } + } else { + cell.fileProgressView?.isHidden = false + cell.fileProgressView?.progress = progressNumber.floatValue + cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCImageCache.images.buttonStop) + let status = userInfo["status"] as? Int ?? NCGlobal.shared.metadataStatusNormal + if status == NCGlobal.shared.metadataStatusDownloading { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↓ " + self.utilityFileSystem.transformedSize(totalBytes) + } else if status == NCGlobal.shared.metadataStatusUploading { + if totalBytes > 0 { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ " + self.utilityFileSystem.transformedSize(totalBytes) + } else { + cell.fileInfoLabel?.text = self.utilityFileSystem.transformedSize(totalBytesExpected) + cell.fileSubinfoLabel?.text = self.infoLabelsSeparator + "↑ …" + } + } + } + } + } + } + // MARK: - Layout + func setNavigationLeftItems() { + navigationItem.title = titleCurrentFolder + } + func getNavigationTitle() -> String { let tableAccount = self.database.getTableAccount(predicate: NSPredicate(format: "account == %@", session.account)) if let tableAccount, @@ -702,6 +822,36 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS func accountSettingsDidDismiss(tableAccount: tableAccount?, controller: NCMainTabBarController?) { } + // MARK: - Empty + + func emptyDataSetView(_ view: NCEmptyView) { + + self.emptyDataSet?.setOffset(getHeaderHeight()) + if isSearchingMode { + view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width) + if self.dataSourceTask?.state == .running { + view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "") + } else { + view.emptyTitle.text = NSLocalizedString("_search_no_record_found_", comment: "") + } + view.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "") + } else if self.dataSourceTask?.state == .running { + view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "") + view.emptyDescription.text = "" + } else { + if serverUrl.isEmpty { + view.emptyImage.image = emptyImage + view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "") + view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "") + } else { + view.emptyImage.image = UIImage(named: "folder_nmcloud") + view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "") + view.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "") + } + } + } + // MARK: - SEARCH func searchController(enabled: Bool) { @@ -745,23 +895,33 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS // MARK: - TAP EVENT - func tapMoreListItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { - tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, image: image, sender: sender) + func tapMoreListItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, image: UIImage?, sender: Any) { + tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, namedButtonMore: namedButtonMore, image: image, sender: sender) } - func tapMorePhotoItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { - tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, image: image, sender: sender) + func tapMorePhotoItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, image: UIImage?, sender: Any) { + tapMoreGridItem(with: ocId, ocIdTransfer: ocIdTransfer, namedButtonMore: namedButtonMore, image: image, sender: sender) } func tapShareListItem(with ocId: String, ocIdTransfer: String, sender: Any) { + if isEditMode { return } guard let metadata = self.database.getMetadataFromOcId(ocId) else { return } - + TealiumHelper.shared.trackEvent(title: "magentacloud-app.filebrowser.sharing", data: ["": ""]) + appDelegate.adjust.trackEvent(TriggerEvent(Sharing.rawValue)) NCActionCenter.shared.openShare(viewController: self, metadata: metadata, page: .sharing) } - func tapMoreGridItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { + func tapMoreGridItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, image: UIImage?, sender: Any) { + if isEditMode { return } guard let metadata = self.database.getMetadataFromOcId(ocId) else { return } - toggleMenu(metadata: metadata, image: image) +// toggleMenu(metadata: metadata, image: image) + if namedButtonMore == NCGlobal.shared.buttonMoreMore || namedButtonMore == NCGlobal.shared.buttonMoreLock { + toggleMenu(metadata: metadata, image: image) + } else if namedButtonMore == NCGlobal.shared.buttonMoreStop { + Task { + await cancelSession(metadata: metadata) + } + } } func tapRichWorkspace(_ sender: Any) { @@ -789,16 +949,50 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS didSelectMetadata(metadata, withOcIds: false) } - func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + func tapButtonSwitch(_ sender: Any) { + guard !isTransitioning else { return } + isTransitioning = true - func longPressGridItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) else { return } - func longPressMoreListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + if layoutForView.layout == NCGlobal.shared.layoutGrid { + layoutForView.layout = NCGlobal.shared.layoutList + } else { + layoutForView.layout = NCGlobal.shared.layoutGrid + } + self.layoutForView = NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) + self.collectionView.reloadData() + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.setCollectionViewLayout(layoutForView.layout == NCGlobal.shared.layoutList ? self.listLayout : self.gridLayout, animated: true) {_ in self.isTransitioning = false } + } - func longPressPhotoItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + func tapButtonOrder(_ sender: Any) { + +// if let titleButtonHeader = NCKeychain().getTitleButtonHeader(account: session.account), !titleButtonHeader.isEmpty { +// layoutForView?.titleButtonHeader = titleButtonHeader +// } +// NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView!) + + let sortMenu = NCSortMenu() + sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) + } - func longPressMoreGridItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + func longPressPhotoItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressListItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func tapShareListItem(with objectId: String, indexPath: IndexPath, sender: Any) { } + func longPressMoreListItem(with ocId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressGridItem(with ocId: String, ocIdTransfer: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func longPressMoreGridItem(with ocId: String, namedButtonMore: String, gestureRecognizer: UILongPressGestureRecognizer) { } + + func tapButtonTransfer(_ sender: Any) { } + + func tapMorePhotoItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) { } + @objc func longPressCollecationView(_ gestureRecognizer: UILongPressGestureRecognizer) { openMenuItems(with: nil, gestureRecognizer: gestureRecognizer) } @@ -853,6 +1047,19 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS // MARK: - DataSource @objc func reloadDataSource() { + + // get auto upload folder + autoUploadFileName = NCManageDatabase.shared.getAccountAutoUploadFileName() + autoUploadDirectory = NCManageDatabase.shared.getAccountAutoUploadDirectory(urlBase: session.urlBase, userId: session.userId, account: session.account) + + // get layout for view + layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) + // set GroupField for Grid + if !isSearchingMode && layoutForView?.layout == NCGlobal.shared.layoutGrid { + groupByField = "classFile" + } else { + groupByField = "name" + } if isSearchingMode { isDirectoryEncrypted = false } else { @@ -860,14 +1067,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } DispatchQueue.main.async { - UIView.transition(with: self.collectionView, - duration: 0.20, - options: .transitionCrossDissolve, - animations: { self.collectionView.reloadData() }, - completion: nil) - - (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() +// UIView.transition(with: self.collectionView, +// duration: 0.20, +// options: .transitionCrossDissolve, +// animations: { self.collectionView.reloadData() }, +// completion: nil) +// +// (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() self.refreshControl.endRefreshing() + self.collectionView.reloadData() + self.setNavigationRightItems() } } @@ -969,39 +1178,56 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } - // MARK: - Header size - - func getHeaderHeight(section: Int) -> (heightHeaderRichWorkspace: CGFloat, - heightHeaderRecommendations: CGFloat, - heightHeaderSection: CGFloat) { - var heightHeaderRichWorkspace: CGFloat = 0 - var heightHeaderRecommendations: CGFloat = 0 - var heightHeaderSection: CGFloat = 0 - - if showDescription, - !isSearchingMode, - let richWorkspaceText = self.richWorkspaceText, - !richWorkspaceText.trimmingCharacters(in: .whitespaces).isEmpty { - heightHeaderRichWorkspace = UIScreen.main.bounds.size.height / 6 - } + func pushViewController(viewController: UIViewController) { + if pushed { return } - if isRecommendationActived, - !isSearchingMode, - NCKeychain().showRecommendedFiles, - !self.database.getRecommendedFiles(account: self.session.account).isEmpty { - heightHeaderRecommendations = self.heightHeaderRecommendations - heightHeaderSection = self.heightHeaderSection - } + pushed = true + navigationController?.pushViewController(viewController, animated: true) + } + + // MARK: - Header size - if isSearchingMode || layoutForView?.groupBy != "none" || self.dataSource.numberOfSections() > 1 { - if section == 0 { - return (heightHeaderRichWorkspace, heightHeaderRecommendations, self.heightHeaderSection) - } else { - return (0, 0, self.heightHeaderSection) - } - } else { - return (heightHeaderRichWorkspace, heightHeaderRecommendations, heightHeaderSection) +// func getHeaderHeight(section: Int) -> (heightHeaderRichWorkspace: CGFloat, +// heightHeaderRecommendations: CGFloat, +// heightHeaderSection: CGFloat) { +// var heightHeaderRichWorkspace: CGFloat = 0 +// var heightHeaderRecommendations: CGFloat = 0 +// var heightHeaderSection: CGFloat = 0 +// +// if showDescription, +// !isSearchingMode, +// let richWorkspaceText = self.richWorkspaceText, +// !richWorkspaceText.trimmingCharacters(in: .whitespaces).isEmpty { +// heightHeaderRichWorkspace = UIScreen.main.bounds.size.height / 6 +// } +// +// if isRecommendationActived, +// !isSearchingMode, +// NCKeychain().showRecommendedFiles, +// !self.database.getRecommendedFiles(account: self.session.account).isEmpty { +// heightHeaderRecommendations = self.heightHeaderRecommendations +// heightHeaderSection = self.heightHeaderSection +// } +// +// if isSearchingMode || layoutForView?.groupBy != "none" || self.dataSource.numberOfSections() > 1 { +// if section == 0 { +// return (heightHeaderRichWorkspace, heightHeaderRecommendations, self.heightHeaderSection) +// } else { +// return (0, 0, self.heightHeaderSection) +// } +// } else { +// return (heightHeaderRichWorkspace, heightHeaderRecommendations, heightHeaderSection) +// } +// } + + func isHeaderMenuTransferViewEnabled() -> [tableMetadata]? { + if headerMenuTransferView, + NCNetworking.shared.isOnline, + let results = database.getResultsMetadatas(predicate: NSPredicate(format: "status IN %@", [global.metadataStatusWaitUpload, global.metadataStatusUploading])), + !results.isEmpty { + return Array(results) } + return nil } func sizeForHeaderInSection(section: Int) -> CGSize { @@ -1010,7 +1236,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS let isIphone = UIDevice.current.userInterfaceIdiom == .phone if self.dataSource.isEmpty() { - height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset) + height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset, isHeaderMenuTransferViewEnabled: isHeaderMenuTransferViewEnabled() != nil) } else if isEditMode || (isLandscape && isIphone) { return CGSize.zero } else {