2020-03-09 23:39:58 +01:00
//
// N e w s B l u r A c c o u n t V i e w C o n t r o l l e r . s w i f t
// N e t N e w s W i r e
//
// C r e a t e d b y A n h - Q u a n g D o o n 3 / 9 / 2 0 .
// C o p y r i g h t ( c ) 2 0 2 0 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-04-16 15:25:40 +02:00
import Secrets
2024-04-02 04:31:57 +02:00
import Web
2020-11-09 14:31:29 +01:00
import SafariServices
2020-03-09 23:39:58 +01:00
class NewsBlurAccountViewController : UITableViewController {
@IBOutlet weak var activityIndicator : UIActivityIndicatorView !
@IBOutlet weak var cancelBarButtonItem : UIBarButtonItem !
2020-03-10 01:19:24 +01:00
@IBOutlet weak var usernameTextField : UITextField !
2020-03-09 23:39:58 +01:00
@IBOutlet weak var passwordTextField : UITextField !
@IBOutlet weak var showHideButton : UIButton !
@IBOutlet weak var actionButton : UIButton !
2020-11-09 14:41:05 +01:00
@IBOutlet weak var footerLabel : UILabel !
2021-06-16 08:41:51 +02:00
@IBOutlet weak var onepasswordButton : UIBarButtonItem ! {
didSet {
onepasswordButton . image ? . withTintColor ( AppAssets . primaryAccentColor )
}
}
2020-03-09 23:39:58 +01:00
weak var account : Account ?
weak var delegate : AddAccountDismissDelegate ?
2024-03-11 06:22:41 +01:00
2020-03-09 23:39:58 +01:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
2020-11-09 14:41:05 +01:00
setupFooter ( )
2020-03-09 23:39:58 +01:00
activityIndicator . isHidden = true
2020-03-10 01:19:24 +01:00
usernameTextField . delegate = self
2020-03-09 23:39:58 +01:00
passwordTextField . delegate = self
2020-03-23 00:52:48 +01:00
if let account = account , let credentials = try ? account . retrieveCredentials ( type : . newsBlurBasic ) {
2020-03-09 23:39:58 +01:00
actionButton . setTitle ( NSLocalizedString ( " Update Credentials " , comment : " Update Credentials " ) , for : . normal )
actionButton . isEnabled = true
2020-03-10 01:19:24 +01:00
usernameTextField . text = credentials . username
2020-03-09 23:39:58 +01:00
passwordTextField . text = credentials . secret
} else {
actionButton . setTitle ( NSLocalizedString ( " Add Account " , comment : " Add Account " ) , for : . normal )
}
2020-03-10 01:19:24 +01:00
NotificationCenter . default . addObserver ( self , selector : #selector ( textDidChange ( _ : ) ) , name : UITextField . textDidChangeNotification , object : usernameTextField )
2020-03-09 23:39:58 +01:00
NotificationCenter . default . addObserver ( self , selector : #selector ( textDidChange ( _ : ) ) , name : UITextField . textDidChangeNotification , object : passwordTextField )
tableView . register ( ImageHeaderView . self , forHeaderFooterViewReuseIdentifier : " SectionHeader " )
}
2020-11-09 14:41:05 +01:00
private func setupFooter ( ) {
2021-06-01 01:01:01 +02:00
footerLabel . text = NSLocalizedString ( " Sign in to your NewsBlur account and sync your feeds across your devices. Your username and password will be encrypted and stored in Keychain. \n \n Don’ t have a NewsBlur account? " , comment : " NewsBlur " )
2020-11-09 14:41:05 +01:00
}
2020-03-09 23:39:58 +01:00
override func tableView ( _ tableView : UITableView , heightForHeaderInSection section : Int ) -> CGFloat {
return section = = 0 ? ImageHeaderView . rowHeight : super . tableView ( tableView , heightForHeaderInSection : section )
}
override func tableView ( _ tableView : UITableView , viewForHeaderInSection section : Int ) -> UIView ? {
if section = = 0 {
let headerView = tableView . dequeueReusableHeaderFooterView ( withIdentifier : " SectionHeader " ) as ! ImageHeaderView
2024-07-08 19:07:26 +02:00
headerView . imageView . image = AppAsset . Account . image ( for : . newsBlur )
2020-03-09 23:39:58 +01:00
return headerView
} else {
return super . tableView ( tableView , viewForHeaderInSection : section )
}
}
@IBAction func cancel ( _ sender : Any ) {
dismiss ( animated : true , completion : nil )
}
@IBAction func showHidePassword ( _ sender : Any ) {
if passwordTextField . isSecureTextEntry {
passwordTextField . isSecureTextEntry = false
showHideButton . setTitle ( " Hide " , for : . normal )
} else {
passwordTextField . isSecureTextEntry = true
showHideButton . setTitle ( " Show " , for : . normal )
}
}
@IBAction func action ( _ sender : Any ) {
2020-03-10 01:19:24 +01:00
guard let username = usernameTextField . text else {
showError ( NSLocalizedString ( " Username required. " , comment : " Credentials Error " ) )
2020-03-09 23:39:58 +01:00
return
}
2020-10-29 20:05:55 +01:00
// W h e n y o u f i l l i n t h e e m a i l a d d r e s s v i a a u t o - c o m p l e t e i t a d d s e x t r a w h i t e s p a c e
let trimmedUsername = username . trimmingCharacters ( in : . whitespaces )
guard account != nil || ! AccountManager . shared . duplicateServiceAccount ( type : . newsBlur , username : trimmedUsername ) else {
showError ( NSLocalizedString ( " There is already a NewsBlur account with that username created. " , comment : " Duplicate Error " ) )
return
}
2024-04-04 06:15:13 +02:00
2020-03-10 01:19:24 +01:00
let password = passwordTextField . text ? ? " "
2020-03-09 23:39:58 +01:00
startAnimatingActivityIndicator ( )
disableNavigation ( )
2024-04-04 06:15:13 +02:00
let credentials = Credentials ( type : . newsBlurBasic , username : trimmedUsername , secret : password )
Task { @ MainActor in
var validationDidThrow = false
var validatedCredentials : Credentials ?
do {
2024-07-08 00:38:45 +02:00
validatedCredentials = try await Account . validateCredentials ( type : . newsBlur , credentials : credentials )
2024-04-04 06:15:13 +02:00
} catch {
self . showError ( error . localizedDescription )
validationDidThrow = true
}
2020-03-09 23:39:58 +01:00
2020-03-23 00:52:48 +01:00
self . stopAnimatingActivityIndicator ( )
2020-03-09 23:39:58 +01:00
self . enableNavigation ( )
2024-04-04 06:15:13 +02:00
if validationDidThrow {
return
}
guard let validatedCredentials else {
self . showError ( NSLocalizedString ( " Invalid username/password combination. " , comment : " Credentials Error " ) )
return
}
if self . account = = nil {
self . account = AccountManager . shared . createAccount ( type : . newsBlur )
}
do {
try self . account ? . removeCredentials ( type : . newsBlurBasic )
2024-04-08 01:09:23 +02:00
try self . account ? . removeCredentials ( type : . newsBlurSessionID )
2024-04-04 06:15:13 +02:00
try self . account ? . storeCredentials ( credentials )
try self . account ? . storeCredentials ( validatedCredentials )
self . refreshAll ( )
self . dismiss ( animated : true , completion : nil )
self . delegate ? . dismiss ( )
} catch {
self . showError ( NSLocalizedString ( " Keychain error while storing credentials. " , comment : " Credentials Error " ) )
2020-03-09 23:39:58 +01:00
}
}
}
2024-04-04 06:15:13 +02:00
private func refreshAll ( ) {
Task { @ MainActor in
do {
try await self . account ? . refreshAll ( )
} catch {
self . presentError ( error )
}
}
}
2020-11-09 14:31:29 +01:00
@IBAction func signUpWithProvider ( _ sender : Any ) {
let url = URL ( string : " https://newsblur.com " ) !
let safari = SFSafariViewController ( url : url )
safari . modalPresentationStyle = . currentContext
self . present ( safari , animated : true , completion : nil )
}
2021-06-16 08:41:51 +02:00
@IBAction func retrievePasswordDetailsFrom1Password ( _ sender : Any ) {
2021-06-17 06:38:53 +02:00
OnePasswordExtension . shared ( ) . findLogin ( forURLString : " newsblur.com " , for : self , sender : sender ) { [ self ] loginDictionary , error in
2021-06-16 08:41:51 +02:00
if let loginDictionary = loginDictionary {
usernameTextField . text = loginDictionary [ AppExtensionUsernameKey ] as ? String
passwordTextField . text = loginDictionary [ AppExtensionPasswordKey ] as ? String
actionButton . isEnabled = ! ( usernameTextField . text ? . isEmpty ? ? false ) && ! ( passwordTextField . text ? . isEmpty ? ? false )
}
}
}
2020-03-09 23:39:58 +01:00
@objc func textDidChange ( _ note : Notification ) {
2020-03-10 01:19:24 +01:00
actionButton . isEnabled = ! ( usernameTextField . text ? . isEmpty ? ? false )
2020-03-09 23:39:58 +01:00
}
private func showError ( _ message : String ) {
presentError ( title : " Error " , message : message )
}
private func enableNavigation ( ) {
self . cancelBarButtonItem . isEnabled = true
self . actionButton . isEnabled = true
}
private func disableNavigation ( ) {
cancelBarButtonItem . isEnabled = false
actionButton . isEnabled = false
}
private func startAnimatingActivityIndicator ( ) {
activityIndicator . isHidden = false
activityIndicator . startAnimating ( )
}
2020-03-23 00:52:48 +01:00
private func stopAnimatingActivityIndicator ( ) {
2020-03-09 23:39:58 +01:00
self . activityIndicator . isHidden = true
self . activityIndicator . stopAnimating ( )
}
}
extension NewsBlurAccountViewController : UITextFieldDelegate {
func textFieldShouldReturn ( _ textField : UITextField ) -> Bool {
textField . resignFirstResponder ( )
return true
}
}