@@ -13,7 +13,7 @@ import Firebase
1313import GoogleMobileAds
1414
1515// taken from: https://developer.apple.com/documentation/uikit/view_controllers/building_a_document_browser-based_app
16- class DocumentViewController : UIViewController , DocumentDelegate , GADBannerViewDelegate {
16+ class DocumentViewController : UIViewController , DocumentDelegate , GADBannerViewDelegate , UISearchBarDelegate {
1717
1818 private var browserTransition : DocumentBrowserTransitioningDelegate ?
1919 public var transitionController : UIDocumentBrowserTransitionController ? {
@@ -33,6 +33,8 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
3333
3434 private var EXTENSION_WHITELIST = [ " pdf " , " doc " , " docx " , " xls " , " xlsx " , " ppt " , " pptx " , " rtf " , " rtfd.zip " , " csv " , " txt " , " jpg " , " jpeg " , " png " , " gif " , " svg " , " pages " , " pages.zip " , " numbers " , " numbers.zip " , " key " , " key.zip " , " mp3 " , " mp4 " , " flv " , " mkv " , " 3gp " , " aac " , " bmp " , " css " , " htm " , " html " , " js " , " json " , " mpeg " , " oga " , " ogv " , " sh " , " tif " , " tiff " , " weba " , " webm " , " webp " , " xhtml " , " xml " ]
3535
36+ @IBOutlet weak var toolBar : UIToolbar !
37+ @IBOutlet weak var searchBar : UISearchBar !
3638 @IBOutlet weak var segmentedControl : ScrollableSegmentedControl !
3739 private var initialSelect = false
3840
@@ -41,7 +43,11 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
4143 @IBOutlet weak var menuButton : UIBarButtonItem !
4244 @IBOutlet weak var bannerView : GADBannerView !
4345 @IBOutlet weak var bannerViewHeight : NSLayoutConstraint !
46+ @IBOutlet weak var barButtonItem : UIBarButtonItem !
4447
48+ private var searchBarHeightWhenShown : NSLayoutConstraint ?
49+ private var searchBarHeightWhenHidden : NSLayoutConstraint ?
50+
4551 private var isFullscreen = false
4652
4753 public var document : Document ? {
@@ -54,6 +60,17 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
5460
5561 override func viewWillAppear( _ animated: Bool ) {
5662 super. viewWillAppear ( animated)
63+
64+ searchBar. delegate = self
65+ searchBar. showsCancelButton = true
66+
67+ searchBarHeightWhenShown = searchBar. heightAnchor. constraint ( equalToConstant: 56 )
68+ searchBarHeightWhenHidden = searchBar. heightAnchor. constraint ( equalToConstant: 0 )
69+
70+ setVCconstraints ( )
71+ hideSearchBar ( )
72+
73+ barButtonItem. title = NSLocalizedString ( " back_to_documents " , comment: " " )
5774
5875 segmentedControl. segmentStyle = . textOnly
5976 segmentedControl. underlineSelected = true
@@ -65,12 +82,37 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
6582 document? . webview = self . webview
6683
6784 bannerView. delegate = self
68- bannerView. adUnitID = " ca-app-pub-3940256099942544/2934735716 "
85+ bannerView. adUnitID = " ca-app-pub-8161473686436957/8123543897 "
6986 bannerView. rootViewController = self
7087
7188 loadBannerAd ( )
7289 }
7390
91+ func setVCconstraints( ) {
92+ searchBar. translatesAutoresizingMaskIntoConstraints = false
93+ bannerView. translatesAutoresizingMaskIntoConstraints = false
94+ segmentedControl. translatesAutoresizingMaskIntoConstraints = false
95+ webview. translatesAutoresizingMaskIntoConstraints = false
96+
97+ searchBar. leadingAnchor. constraint ( equalTo: view. leadingAnchor) . isActive = true
98+ searchBar. trailingAnchor. constraint ( equalTo: view. trailingAnchor) . isActive = true
99+ searchBar. topAnchor. constraint ( equalTo: toolBar. bottomAnchor) . isActive = true
100+
101+ bannerView. leadingAnchor. constraint ( equalTo: view. leadingAnchor) . isActive = true
102+ bannerView. trailingAnchor. constraint ( equalTo: view. trailingAnchor) . isActive = true
103+ bannerView. topAnchor. constraint ( equalTo: searchBar. bottomAnchor) . isActive = true
104+ bannerView. heightAnchor. constraint ( equalToConstant: 50 ) . isActive = true
105+
106+ segmentedControl. topAnchor. constraint ( equalTo: bannerView. bottomAnchor) . isActive = true
107+ segmentedControl. leadingAnchor. constraint ( equalTo: view. leadingAnchor) . isActive = true
108+ segmentedControl. trailingAnchor. constraint ( equalTo: view. trailingAnchor) . isActive = true
109+
110+ webview. topAnchor. constraint ( equalTo: segmentedControl. bottomAnchor) . isActive = true
111+ webview. leadingAnchor. constraint ( equalTo: view. leadingAnchor) . isActive = true
112+ webview. trailingAnchor. constraint ( equalTo: view. trailingAnchor) . isActive = true
113+ webview. bottomAnchor. constraint ( equalTo: view. bottomAnchor) . isActive = true
114+ }
115+
74116 func loadBannerAd( ) {
75117 if ConfigurationManager . manager. configuration == . lite {
76118 let frame = { ( ) -> CGRect in
@@ -142,6 +184,58 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
142184 return isFullscreen
143185 }
144186
187+ func searchBarCancelButtonClicked( _ searchBar: UISearchBar ) {
188+ hideSearchBar ( )
189+ }
190+
191+ func searchBarResultsListButtonClicked( _ searchBar: UISearchBar ) {
192+ if let searchText = searchBar. text {
193+ findNext ( searchText: searchText)
194+ }
195+ }
196+
197+ func searchBar( _ searchBar: UISearchBar , textDidChange searchText: String ) {
198+ findAll ( searchText: searchText)
199+ }
200+
201+ @IBAction func searchButton( _ sender: UIBarButtonItem ) {
202+ showSearchBar ( )
203+ }
204+
205+ private func showSearchBar( ) {
206+ searchBar. becomeFirstResponder ( )
207+ searchBar. isHidden = false
208+ searchBarHeightWhenHidden? . isActive = false
209+ searchBarHeightWhenShown? . isActive = true
210+ }
211+
212+ private func hideSearchBar( ) {
213+ searchBar. text = " "
214+ searchBar. isHidden = true
215+ searchBarHeightWhenHidden? . isActive = true
216+ searchBarHeightWhenShown? . isActive = false
217+
218+ self . view. endEditing ( true )
219+ }
220+
221+ private func findNext( searchText: String ) {
222+ webview? . evaluateJavaScript ( " odr.searchNext( \" " + searchText + " \" ) " , completionHandler: { ( value: Any!, error: Error!) - > Void in
223+ if error != nil {
224+ Crashlytics . crashlytics ( ) . record ( error: error)
225+ fatalError ( " search failed " )
226+ }
227+ } )
228+ }
229+
230+ private func findAll( searchText: String ) {
231+ webview? . evaluateJavaScript ( " odr.search( \" " + searchText + " \" ) " , completionHandler: { ( value: Any!, error: Error!) - > Void in
232+ if error != nil {
233+ Crashlytics . crashlytics ( ) . record ( error: error)
234+ fatalError ( " search failed " )
235+ }
236+ } )
237+ }
238+
145239 @IBAction func returnToDocuments( _ sender: Any ) {
146240 guard let doc = document else {
147241 fatalError ( " document is null " )
@@ -160,8 +254,11 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
160254 alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " yes " , comment: " " ) , style: . default, handler: { ( _) in
161255 Analytics . logEvent ( " alert_unsaved_changes_yes " , parameters: nil )
162256
163- self . saveContent ( )
164- self . closeCurrentDocument ( )
257+ self . saveContent ( ) { ( success) -> ( ) in
258+ if ( success) {
259+ self . closeCurrentDocument ( )
260+ }
261+ }
165262 } ) )
166263
167264 self . present ( alert, animated: true , completion: nil )
@@ -193,8 +290,8 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
193290 }
194291
195292 if document? . edit ?? false {
196- alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " menu_save " , comment: " " ) , style: . default, handler: { ( _) in
197- self . saveContent ( )
293+ alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " action_edit_save " , comment: " " ) , style: . default, handler: { ( _) in
294+ self . saveContent ( completion : nil )
198295 } ) )
199296
200297 alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " menu_discard_changes " , comment: " " ) , style: . default, handler: { ( _) in
@@ -208,7 +305,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
208305 alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " menu_cloud_print " , comment: " " ) , style: . default, handler: { ( _) in
209306 self . printDocument ( )
210307 } ) )
211- alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " menu_help " , comment: " " ) , style: . default, handler: { ( _) in
308+ alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " action_edit_help " , comment: " " ) , style: . default, handler: { ( _) in
212309 self . showWebsite ( )
213310 } ) )
214311 alert. addAction ( UIAlertAction ( title: NSLocalizedString ( " cancel " , comment: " " ) , style: . cancel, handler: nil ) )
@@ -229,7 +326,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
229326 doc. edit = true
230327 }
231328
232- func saveContent( ) {
329+ func saveContent( completion : ( ( Bool ) -> ( ) ) ? ) {
233330 Analytics . logEvent ( " menu_edit_save " , parameters: nil )
234331
235332 guard let doc = document else {
@@ -242,14 +339,16 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
242339 let message : String
243340 let color : UIColor
244341 if success {
245- message = NSLocalizedString ( " alert_document_saved " , comment: " " )
342+ message = NSLocalizedString ( " toast_edit_status_saved " , comment: " " )
246343 color = . green
247344 } else {
248- message = NSLocalizedString ( " alert_error_save_failed " , comment: " " )
345+ message = NSLocalizedString ( " toast_error_save_failed " , comment: " " )
249346 color = . red
250347 }
251348
252- self . showToast ( controller: self , message: message, seconds: 1.5 , color: color)
349+ self . showToast ( controller: self , message: message, seconds: 1.5 , color: color) {
350+ completion ? ( success)
351+ }
253352 }
254353 }
255354
@@ -297,7 +396,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
297396
298397 func documentUpdateContent( _ doc: Document ) {
299398 guard let path = document? . result else {
300- self . webview. loadHTMLString ( " <html><h1>Loading </h1></html> " , baseURL: nil )
399+ self . webview. loadHTMLString ( " <html><h1> \( NSLocalizedString ( " loading " , comment : " " ) ) </h1></html> " , baseURL: nil )
301400
302401 return
303402 }
@@ -315,7 +414,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
315414 } )
316415 }
317416
318- let alert = UIAlertController ( title: NSLocalizedString ( " alert_error_password_protected " , comment: " " ) , message: NSLocalizedString ( " alert_enter_password " , comment : " " ) , preferredStyle: . alert)
417+ let alert = UIAlertController ( title: NSLocalizedString ( " toast_error_password_protected " , comment: " " ) , message: " " , preferredStyle: . alert)
319418 alert. addTextField { ( textField) in
320419 textField. text = " "
321420 }
@@ -332,9 +431,12 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
332431 }
333432
334433 func documentLoadingError( _ doc: Document , errorCode: Int ) {
434+ // attention: wrong for extensions like ".pages.zip"
335435 let fileType = doc. fileURL. pathExtension. lowercased ( )
436+
437+ let fileName = doc. fileURL. absoluteString. lowercased ( )
336438 for type in EXTENSION_WHITELIST {
337- if ( !fileType . starts ( with : type) ) {
439+ if ( !fileName . hasSuffix ( type) ) {
338440 continue
339441 }
340442
@@ -350,7 +452,7 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
350452 return ;
351453 }
352454
353- self . webview. loadHTMLString ( " <html><h1>Error </h1>Failed to load given document. Please try another one while we are working hard to support as many documents as possible. Feel free to contact us via support@opendocument.app for further questions. </html> " , baseURL: nil )
455+ self . webview. loadHTMLString ( " <html><h1> \( NSLocalizedString ( " error " , comment : " " ) ) </h1> \( NSLocalizedString ( " toast_error_generic " , comment : " " ) ) </html> " , baseURL: nil )
354456
355457 Analytics . logEvent (
356458 " load_error " ,
@@ -390,8 +492,14 @@ class DocumentViewController: UIViewController, DocumentDelegate, GADBannerViewD
390492
391493 i += 1
392494 }
393-
394- segmentedControl. isHidden = i <= 1
495+
496+ if i <= 1 {
497+ segmentedControl. heightAnchor. constraint ( equalToConstant: 0 ) . isActive = true
498+ segmentedControl. isHidden = true
499+ } else {
500+ segmentedControl. heightAnchor. constraint ( equalToConstant: 40 ) . isActive = true
501+ segmentedControl. isHidden = false
502+ }
395503
396504 initialSelect = true
397505 segmentedControl. selectedSegmentIndex = 0
0 commit comments