2019-11-07 13:40:10 +01:00
//
2019-11-15 03:11:41 +01:00
// W e b F e e d I n s p e c t o r V i e w C o n t r o l l e r . s w i f t
2019-11-07 13:40:10 +01:00
// N e t N e w s W i r e - i O S
//
// C r e a t e d b y M a u r i c e P a r k e r o n 1 1 / 6 / 1 9 .
// C o p y r i g h t © 2 0 1 9 R a n c h e r o S o f t w a r e . A l l r i g h t s r e s e r v e d .
//
import UIKit
import Account
2020-01-11 22:31:47 +01:00
import SafariServices
2020-05-18 02:39:22 +02:00
import UserNotifications
2019-11-07 13:40:10 +01:00
2019-11-15 03:11:41 +01:00
class WebFeedInspectorViewController : UITableViewController {
2019-11-07 13:40:10 +01:00
2019-11-14 00:02:14 +01:00
static let preferredContentSizeForFormSheetDisplay = CGSize ( width : 460.0 , height : 500.0 )
2019-11-07 13:40:10 +01:00
2019-11-15 03:11:41 +01:00
var webFeed : WebFeed !
2019-11-07 13:40:10 +01:00
@IBOutlet weak var nameTextField : UITextField !
@IBOutlet weak var notifyAboutNewArticlesSwitch : UISwitch !
@IBOutlet weak var alwaysShowReaderViewSwitch : UISwitch !
@IBOutlet weak var homePageLabel : InteractiveLabel !
@IBOutlet weak var feedURLLabel : InteractiveLabel !
private var headerView : InspectorIconHeaderView ?
private var iconImage : IconImage {
2019-11-15 03:11:41 +01:00
if let feedIcon = appDelegate . webFeedIconDownloader . icon ( for : webFeed ) {
2019-11-07 13:40:10 +01:00
return feedIcon
}
2020-01-07 22:17:00 +01:00
if let favicon = appDelegate . faviconDownloader . faviconAsIcon ( for : webFeed ) {
2019-11-07 13:40:10 +01:00
return favicon
}
2019-11-15 03:11:41 +01:00
return FaviconGenerator . favicon ( webFeed )
2019-11-07 13:40:10 +01:00
}
2020-01-11 22:31:47 +01:00
private let homePageIndexPath = IndexPath ( row : 0 , section : 1 )
2020-02-06 14:27:49 +01:00
private var shouldHideHomePageSection : Bool {
return webFeed . homePageURL = = nil
}
2020-05-18 02:39:22 +02:00
private var userNotificationSettings : UNNotificationSettings ?
2019-11-07 13:40:10 +01:00
override func viewDidLoad ( ) {
tableView . register ( InspectorIconHeaderView . self , forHeaderFooterViewReuseIdentifier : " SectionHeader " )
2019-11-15 03:11:41 +01:00
navigationItem . title = webFeed . nameForDisplay
nameTextField . text = webFeed . nameForDisplay
2019-11-07 13:40:10 +01:00
2019-11-15 03:11:41 +01:00
notifyAboutNewArticlesSwitch . setOn ( webFeed . isNotifyAboutNewArticles ? ? false , animated : false )
alwaysShowReaderViewSwitch . setOn ( webFeed . isArticleExtractorAlwaysOn ? ? false , animated : false )
2019-11-07 13:40:10 +01:00
2020-07-06 17:06:12 +02:00
homePageLabel . text = webFeed . homePageURL ? . decodedURLString
feedURLLabel . text = webFeed . url . decodedURLString
2019-11-07 13:40:10 +01:00
2019-11-15 03:11:41 +01:00
NotificationCenter . default . addObserver ( self , selector : #selector ( webFeedIconDidBecomeAvailable ( _ : ) ) , name : . WebFeedIconDidBecomeAvailable , object : nil )
2020-05-18 02:39:22 +02:00
2020-05-18 03:23:42 +02:00
NotificationCenter . default . addObserver ( self , selector : #selector ( updateNotificationSettings ) , name : UIApplication . willEnterForegroundNotification , object : nil )
2020-05-18 02:39:22 +02:00
}
override func viewDidAppear ( _ animated : Bool ) {
updateNotificationSettings ( )
2019-11-07 13:40:10 +01:00
}
override func viewDidDisappear ( _ animated : Bool ) {
2019-11-15 03:11:41 +01:00
if nameTextField . text != webFeed . nameForDisplay {
2019-11-07 13:40:10 +01:00
let nameText = nameTextField . text ? ? " "
2019-11-15 03:11:41 +01:00
let newName = nameText . isEmpty ? ( webFeed . name ? ? NSLocalizedString ( " Untitled " , comment : " Feed name " ) ) : nameText
webFeed . rename ( to : newName ) { _ in }
2019-11-07 13:40:10 +01:00
}
}
// MARK: N o t i f i c a t i o n s
2019-11-15 03:11:41 +01:00
@objc func webFeedIconDidBecomeAvailable ( _ notification : Notification ) {
2019-11-07 13:40:10 +01:00
headerView ? . iconView . iconImage = iconImage
}
@IBAction func notifyAboutNewArticlesChanged ( _ sender : Any ) {
2020-05-18 02:39:22 +02:00
guard let settings = userNotificationSettings else {
notifyAboutNewArticlesSwitch . isOn = ! notifyAboutNewArticlesSwitch . isOn
return
}
if settings . authorizationStatus = = . denied {
notifyAboutNewArticlesSwitch . isOn = ! notifyAboutNewArticlesSwitch . isOn
present ( notificationUpdateErrorAlert ( ) , animated : true , completion : nil )
} else if settings . authorizationStatus = = . authorized {
webFeed . isNotifyAboutNewArticles = notifyAboutNewArticlesSwitch . isOn
} else {
UNUserNotificationCenter . current ( ) . requestAuthorization ( options : [ . badge , . sound , . alert ] ) { ( granted , error ) in
self . updateNotificationSettings ( )
if granted {
DispatchQueue . main . async {
self . webFeed . isNotifyAboutNewArticles = self . notifyAboutNewArticlesSwitch . isOn
UIApplication . shared . registerForRemoteNotifications ( )
}
} else {
DispatchQueue . main . async {
self . notifyAboutNewArticlesSwitch . isOn = ! self . notifyAboutNewArticlesSwitch . isOn
}
}
}
}
2019-11-07 13:40:10 +01:00
}
@IBAction func alwaysShowReaderViewChanged ( _ sender : Any ) {
2019-11-15 03:11:41 +01:00
webFeed . isArticleExtractorAlwaysOn = alwaysShowReaderViewSwitch . isOn
2019-11-07 13:40:10 +01:00
}
@IBAction func done ( _ sender : Any ) {
dismiss ( animated : true )
}
2020-02-06 14:27:49 +01:00
// / R e t u r n s a n e w i n d e x P a t h , t a k i n g i n t o c o n s i d e r a t i o n a n y
// / c o n d i t i o n s t h a t m a y r e q u i r e t h e t a b l e V i e w t o b e
// / d i s p l a y e d d i f f e r e n t l y t h a n w h a t i s s e t u p i n t h e s t o r y b o a r d .
private func shift ( _ indexPath : IndexPath ) -> IndexPath {
return IndexPath ( row : indexPath . row , section : shift ( indexPath . section ) )
}
// / R e t u r n s a n e w s e c t i o n , t a k i n g i n t o c o n s i d e r a t i o n a n y
// / c o n d i t i o n s t h a t m a y r e q u i r e t h e t a b l e V i e w t o b e
// / d i s p l a y e d d i f f e r e n t l y t h a n w h a t i s s e t u p i n t h e s t o r y b o a r d .
private func shift ( _ section : Int ) -> Int {
if section >= homePageIndexPath . section && shouldHideHomePageSection {
return section + 1
}
return section
}
2019-11-07 13:40:10 +01:00
}
// MARK: T a b l e V i e w
2019-11-15 03:11:41 +01:00
extension WebFeedInspectorViewController {
2020-02-06 14:27:49 +01:00
override func numberOfSections ( in tableView : UITableView ) -> Int {
let numberOfSections = super . numberOfSections ( in : tableView )
return shouldHideHomePageSection ? numberOfSections - 1 : numberOfSections
}
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
return super . tableView ( tableView , numberOfRowsInSection : shift ( section ) )
}
2019-11-07 13:40:10 +01:00
override func tableView ( _ tableView : UITableView , heightForHeaderInSection section : Int ) -> CGFloat {
2020-02-06 14:27:49 +01:00
return section = = 0 ? ImageHeaderView . rowHeight : super . tableView ( tableView , heightForHeaderInSection : shift ( section ) )
}
override func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell {
super . tableView ( tableView , cellForRowAt : shift ( indexPath ) )
}
override func tableView ( _ tableView : UITableView , titleForHeaderInSection section : Int ) -> String ? {
super . tableView ( tableView , titleForHeaderInSection : shift ( section ) )
2019-11-07 13:40:10 +01:00
}
override func tableView ( _ tableView : UITableView , viewForHeaderInSection section : Int ) -> UIView ? {
2020-02-06 14:27:49 +01:00
if shift ( section ) = = 0 {
2019-11-07 13:40:10 +01:00
headerView = tableView . dequeueReusableHeaderFooterView ( withIdentifier : " SectionHeader " ) as ? InspectorIconHeaderView
headerView ? . iconView . iconImage = iconImage
return headerView
} else {
2020-02-06 14:27:49 +01:00
return super . tableView ( tableView , viewForHeaderInSection : shift ( section ) )
2019-11-07 13:40:10 +01:00
}
}
2020-01-11 22:31:47 +01:00
override func tableView ( _ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) {
2020-02-06 14:27:49 +01:00
if shift ( indexPath ) = = homePageIndexPath ,
2020-01-11 22:31:47 +01:00
let homePageUrlString = webFeed . homePageURL ,
let homePageUrl = URL ( string : homePageUrlString ) {
let safari = SFSafariViewController ( url : homePageUrl )
2020-01-12 22:29:32 +01:00
safari . modalPresentationStyle = . pageSheet
2020-01-12 22:53:08 +01:00
present ( safari , animated : true ) {
tableView . deselectRow ( at : indexPath , animated : true )
}
2020-01-11 22:31:47 +01:00
}
}
2019-11-07 13:40:10 +01:00
}
// MARK: U I T e x t F i e l d D e l e g a t e
2019-11-15 03:11:41 +01:00
extension WebFeedInspectorViewController : UITextFieldDelegate {
2019-11-07 13:40:10 +01:00
func textFieldShouldReturn ( _ textField : UITextField ) -> Bool {
textField . resignFirstResponder ( )
return true
}
}
2020-05-18 02:39:22 +02:00
// MARK: U N U s e r N o t i f i c a t i o n C e n t e r
extension WebFeedInspectorViewController {
2020-05-18 03:23:42 +02:00
@objc
2020-05-18 02:39:22 +02:00
func updateNotificationSettings ( ) {
UNUserNotificationCenter . current ( ) . getNotificationSettings { ( settings ) in
DispatchQueue . main . async {
self . userNotificationSettings = settings
if settings . authorizationStatus = = . authorized {
UIApplication . shared . registerForRemoteNotifications ( )
}
}
}
}
func notificationUpdateErrorAlert ( ) -> UIAlertController {
let alert = UIAlertController ( title : NSLocalizedString ( " Enable Notifications " , comment : " Notifications " ) ,
message : NSLocalizedString ( " Notifications need to be enabled in the Settings app. " , comment : " Notifications need to be enabled in the Settings app. " ) , preferredStyle : . alert )
let openSettings = UIAlertAction ( title : NSLocalizedString ( " Open Settings " , comment : " Open Settings " ) , style : . default ) { ( action ) in
UIApplication . shared . open ( URL ( string : UIApplication . openSettingsURLString ) ! , options : [ UIApplication . OpenExternalURLOptionsKey . universalLinksOnly : false ] , completionHandler : nil )
}
let dismiss = UIAlertAction ( title : NSLocalizedString ( " Dismiss " , comment : " Dismiss " ) , style : . cancel , handler : nil )
alert . addAction ( openSettings )
alert . addAction ( dismiss )
return alert
}
}