2017-02-02 21:04:31 +08:00
//
// P a s s w o r d D e t a i l T a b l e V i e w C o n t r o l l e r . s w i f t
// p a s s
//
// C r e a t e d b y M i n g s h e n S u n o n 2 / 2 / 2 0 1 7 .
// C o p y r i g h t © 2 0 1 7 B o b S u n . A l l r i g h t s r e s e r v e d .
//
import UIKit
2017-02-09 13:17:11 +08:00
import FavIcon
2017-02-15 20:01:17 +08:00
import SVProgressHUD
2017-06-13 11:42:49 +08:00
import passKit
2017-02-02 21:04:31 +08:00
2017-02-05 00:35:23 +08:00
class PasswordDetailTableViewController : UITableViewController , UIGestureRecognizerDelegate {
2017-02-02 21:04:31 +08:00
var passwordEntity : PasswordEntity ?
2017-03-22 01:39:26 +08:00
private var password : Password ?
private var passwordImage : UIImage ?
private var oneTimePasswordIndexPath : IndexPath ?
private var shouldPopCurrentView = false
private let passwordStore = PasswordStore . shared
2017-02-28 12:25:52 +08:00
2017-03-22 01:39:26 +08:00
private lazy var editUIBarButtonItem : UIBarButtonItem = {
2017-02-28 17:33:45 +08:00
let uiBarButtonItem = UIBarButtonItem ( barButtonSystemItem : . edit , target : self , action : #selector ( pressEdit ( _ : ) ) )
return uiBarButtonItem
} ( )
2017-02-28 12:25:52 +08:00
2017-03-22 01:39:26 +08:00
private struct TableCell {
2017-02-02 21:04:31 +08:00
var title : String
var content : String
2017-02-09 15:47:42 +08:00
init ( ) {
title = " "
content = " "
}
2017-03-31 00:28:37 -07:00
init ( title : String ) {
self . title = title
self . content = " "
}
2017-02-09 15:47:42 +08:00
init ( title : String , content : String ) {
self . title = title
self . content = content
}
2017-02-02 21:04:31 +08:00
}
2017-03-22 01:39:26 +08:00
private struct TableSection {
2017-03-31 00:28:37 -07:00
var type : PasswordDetailTableViewControllerSectionType
var header : String ?
2017-02-04 20:38:40 +08:00
var item : Array < TableCell >
2017-03-31 00:28:37 -07:00
init ( type : PasswordDetailTableViewControllerSectionType ) {
self . type = type
header = nil
item = [ TableCell ] ( )
}
init ( type : PasswordDetailTableViewControllerSectionType , header : String ) {
self . init ( type : type )
self . header = header
}
2017-02-04 20:38:40 +08:00
}
2017-03-22 01:39:26 +08:00
private var tableData = Array < TableSection > ( )
2017-02-02 21:04:31 +08:00
2017-03-31 00:28:37 -07:00
private enum PasswordDetailTableViewControllerSectionType {
case name , main , addition , misc
}
2017-02-02 21:04:31 +08:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
tableView . register ( UINib ( nibName : " LabelTableViewCell " , bundle : nil ) , forCellReuseIdentifier : " labelCell " )
2017-02-06 20:48:20 +08:00
tableView . register ( UINib ( nibName : " PasswordDetailTitleTableViewCell " , bundle : nil ) , forCellReuseIdentifier : " passwordDetailTitleTableViewCell " )
2017-02-05 00:35:23 +08:00
let tapGesture = UITapGestureRecognizer ( target : self , action : #selector ( PasswordDetailTableViewController . tapMenu ( recognizer : ) ) )
2017-03-31 22:44:30 -07:00
tapGesture . cancelsTouchesInView = false
2017-02-05 00:35:23 +08:00
tableView . addGestureRecognizer ( tapGesture )
tapGesture . delegate = self
2017-02-05 14:08:19 +08:00
2017-03-29 22:16:57 -07:00
tableView . contentInset = UIEdgeInsetsMake ( - 36 , 0 , 44 , 0 ) ;
2017-02-05 14:08:19 +08:00
tableView . rowHeight = UITableViewAutomaticDimension
tableView . estimatedRowHeight = 52
2017-02-28 12:25:52 +08:00
2017-02-15 21:25:03 +08:00
editUIBarButtonItem . isEnabled = false
navigationItem . rightBarButtonItem = editUIBarButtonItem
2017-10-07 10:42:09 -07:00
if #available ( iOS 11.0 , * ) {
navigationItem . largeTitleDisplayMode = . never
}
2017-02-06 15:03:34 +08:00
2018-11-10 22:38:12 -08:00
if let imageData = passwordEntity ? . getImage ( ) {
2017-02-09 14:41:59 +08:00
let image = UIImage ( data : imageData as Data )
passwordImage = image
}
2017-04-23 10:03:09 -07:00
self . decryptThenShowPassword ( )
2017-03-22 01:39:26 +08:00
self . setupOneTimePasswordAutoRefresh ( )
2017-03-24 20:40:24 +08:00
// p o p t h e c u r r e n t v i e w b e c a u s e t h i s p a s s w o r d m i g h t b e " d i s c a r d e d "
2017-03-22 01:39:26 +08:00
NotificationCenter . default . addObserver ( self , selector : #selector ( setShouldPopCurrentView ) , name : . passwordStoreChangeDiscarded , object : nil )
2017-03-24 20:40:24 +08:00
// r e s e t t h e d a t a t a b l e i f s o m e p a s s w o r d ( m a y b e a n o t h e r o n e ) h a s b e e n u p d a t e d
2017-06-03 17:50:33 -07:00
NotificationCenter . default . addObserver ( self , selector : #selector ( decryptThenShowPassword ) , name : . passwordStoreUpdated , object : nil )
2017-03-24 20:40:24 +08:00
// r e s e t t h e d a t a t a b l e i f t h e d i s a p l y s e t t i n g s h a v e b e e n c h a n g e d
2017-06-03 17:50:33 -07:00
NotificationCenter . default . addObserver ( self , selector : #selector ( decryptThenShowPassword ) , name : . passwordDetailDisplaySettingChanged , object : nil )
2017-03-22 01:39:26 +08:00
}
override func viewDidAppear ( _ animated : Bool ) {
super . viewWillAppear ( animated )
if self . shouldPopCurrentView {
let alert = UIAlertController ( title : " Notice " , message : " All previous local changes have been discarded. Your current Password Store will be shown. " , preferredStyle : UIAlertControllerStyle . alert )
alert . addAction ( UIAlertAction ( title : " OK " , style : UIAlertActionStyle . default , handler : { _ in
_ = self . navigationController ? . popViewController ( animated : true )
} ) )
self . present ( alert , animated : true , completion : nil )
}
2017-02-28 12:25:52 +08:00
}
2017-04-23 10:03:09 -07:00
private func requestPGPKeyPassphrase ( ) -> String {
let sem = DispatchSemaphore ( value : 0 )
var passphrase = " "
DispatchQueue . main . async {
let alert = UIAlertController ( title : " Passphrase " , message : " Please fill in the passphrase of your PGP secret key. " , preferredStyle : UIAlertControllerStyle . alert )
alert . addAction ( UIAlertAction ( title : " OK " , style : UIAlertActionStyle . default , handler : { _ in
passphrase = alert . textFields ! . first ! . text !
sem . signal ( )
} ) )
alert . addTextField ( configurationHandler : { ( textField : UITextField ! ) in
textField . text = " "
textField . isSecureTextEntry = true
} )
self . present ( alert , animated : true , completion : nil )
}
let _ = sem . wait ( timeout : DispatchTime . distantFuture )
2017-10-08 21:37:58 +08:00
if SharedDefaults [ . isRememberPGPPassphraseOn ] {
2017-03-16 22:39:03 -07:00
self . passwordStore . pgpKeyPassphrase = passphrase
2017-02-28 12:25:52 +08:00
}
2017-04-23 10:03:09 -07:00
return passphrase
}
2017-06-03 17:50:33 -07:00
@objc private func decryptThenShowPassword ( ) {
2018-11-10 22:38:12 -08:00
guard let passwordEntity = passwordEntity else {
2017-06-03 17:50:33 -07:00
Utils . alert ( title : " Cannot Show Password " , message : " The password does not exist. " , controller : self , handler : { ( UIAlertAction ) -> Void in
self . navigationController ! . popViewController ( animated : true )
} )
return
}
2017-02-08 18:57:15 +08:00
DispatchQueue . global ( qos : . userInitiated ) . async {
2017-03-22 00:22:47 +08:00
// d e c r y p t p a s s w o r d
2017-02-06 15:03:34 +08:00
do {
2017-06-03 17:50:33 -07:00
self . password = try self . passwordStore . decrypt ( passwordEntity : passwordEntity , requestPGPKeyPassphrase : self . requestPGPKeyPassphrase )
2017-02-06 15:03:34 +08:00
} catch {
2017-02-22 12:56:06 +08:00
DispatchQueue . main . async {
2017-05-08 21:12:48 +08:00
// r e m o v e t h e w r o n g p a s s p h r a s e s o t h a t u s e r s c o u l d e n t e r i t n e x t t i m e
self . passwordStore . pgpKeyPassphrase = nil
2017-06-07 21:11:01 +08:00
// a l e r t : c a n c e l o r t r y a g a i n
let alert = UIAlertController ( title : " Cannot Show Password " , message : error . localizedDescription , preferredStyle : UIAlertControllerStyle . alert )
alert . addAction ( UIAlertAction ( title : " Cancel " , style : UIAlertActionStyle . default ) { _ in
2017-02-22 12:56:06 +08:00
self . navigationController ! . popViewController ( animated : true )
2017-06-03 17:50:33 -07:00
} )
2017-06-07 21:11:01 +08:00
alert . addAction ( UIAlertAction ( title : " Try again " , style : UIAlertActionStyle . destructive ) { _ in
self . decryptThenShowPassword ( )
} )
self . present ( alert , animated : true , completion : nil )
2017-02-22 12:56:06 +08:00
}
return
2017-02-06 15:03:34 +08:00
}
2017-03-22 00:22:47 +08:00
// d i s p l a y p a s s w o r d
self . showPassword ( )
2017-02-28 12:25:52 +08:00
}
}
2017-06-03 17:50:33 -07:00
private func showPassword ( ) {
2017-03-22 00:22:47 +08:00
DispatchQueue . main . async { [ weak self ] in
self ? . setTableData ( )
2017-04-10 22:09:39 -07:00
self ? . tableView . reloadData ( )
2017-03-22 00:22:47 +08:00
self ? . editUIBarButtonItem . isEnabled = true
2018-06-23 20:42:56 +02:00
if let urlString = self ? . password ? . urlString {
2018-11-10 22:38:12 -08:00
if self ? . passwordEntity ? . getImage ( ) = = nil {
2017-03-22 00:22:47 +08:00
self ? . updatePasswordImage ( urlString : urlString )
}
2017-02-09 13:17:11 +08:00
}
}
}
2017-03-22 01:39:26 +08:00
private func setupOneTimePasswordAutoRefresh ( ) {
2017-03-05 02:54:36 +08:00
Timer . scheduledTimer ( withTimeInterval : 1 , repeats : true ) {
[ weak self ] timer in
// b a i l o u t o f t h e t i m e r c o d e i f t h e o b j e c t h a s b e e n f r e e d
guard let strongSelf = self ,
2017-03-24 23:14:44 +08:00
let otpType = strongSelf . password ? . otpType ,
otpType != . none ,
2017-03-05 02:54:36 +08:00
let indexPath = strongSelf . oneTimePasswordIndexPath ,
let cell = strongSelf . tableView . cellForRow ( at : indexPath ) as ? LabelTableViewCell else {
return
}
2017-03-24 23:14:44 +08:00
switch otpType {
case . totp :
2017-03-07 09:50:18 +08:00
if let ( title , otp ) = strongSelf . password ? . getOtpStrings ( ) {
strongSelf . tableData [ indexPath . section ] . item [ indexPath . row ] . title = title
2017-03-05 02:54:36 +08:00
strongSelf . tableData [ indexPath . section ] . item [ indexPath . row ] . content = otp
2017-03-07 09:50:18 +08:00
cell . cellData ? . title = title
2017-03-05 02:54:36 +08:00
cell . cellData ? . content = otp
}
2017-03-07 09:50:18 +08:00
default :
break
2017-03-05 02:54:36 +08:00
}
}
}
2017-03-22 01:39:26 +08:00
@objc private func pressEdit ( _ sender : Any ? ) {
2017-02-13 01:15:42 +08:00
performSegue ( withIdentifier : " editPasswordSegue " , sender : self )
}
2017-03-22 01:39:26 +08:00
@objc private func setShouldPopCurrentView ( ) {
self . shouldPopCurrentView = true
}
@IBAction private func cancelEditPassword ( segue : UIStoryboardSegue ) {
2017-02-13 01:15:42 +08:00
}
2017-03-22 01:39:26 +08:00
@IBAction private func saveEditPassword ( segue : UIStoryboardSegue ) {
2017-04-25 13:01:17 -07:00
if self . password ! . changed != 0 {
2017-02-15 20:01:17 +08:00
SVProgressHUD . show ( withStatus : " Saving " )
2017-04-25 13:01:17 -07:00
do {
self . passwordEntity = try self . passwordStore . edit ( passwordEntity : self . passwordEntity ! , password : self . password ! )
} catch {
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-02-15 20:01:17 +08:00
}
2017-04-25 13:01:17 -07:00
self . setTableData ( )
self . tableView . reloadData ( )
SVProgressHUD . showSuccess ( withStatus : " Success " )
SVProgressHUD . dismiss ( withDelay : 1 )
2017-02-13 01:15:42 +08:00
}
}
2017-03-21 13:34:26 -07:00
@IBAction private func deletePassword ( segue : UIStoryboardSegue ) {
2017-04-25 13:01:17 -07:00
do {
try passwordStore . delete ( passwordEntity : passwordEntity ! )
} catch {
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
}
2017-03-22 17:40:04 -07:00
let _ = navigationController ? . popViewController ( animated : true )
2017-03-21 13:16:25 -07:00
}
2017-03-21 13:34:26 -07:00
2017-03-22 01:39:26 +08:00
private func setTableData ( ) {
2017-02-13 01:15:42 +08:00
self . tableData = Array < TableSection > ( )
2017-03-31 00:28:37 -07:00
// n a m e s e c t i o n
var section = TableSection ( type : . name )
section . item . append ( TableCell ( ) )
tableData . append ( section )
// m a i n s e c t i o n
section = TableSection ( type : . main )
2017-02-13 01:15:42 +08:00
let password = self . password !
2018-06-23 20:42:56 +02:00
if let username = password . username {
2017-03-31 00:28:37 -07:00
section . item . append ( TableCell ( title : " username " , content : username ) )
2017-02-13 01:15:42 +08:00
}
2018-06-23 20:42:56 +02:00
if let login = password . login {
2017-06-28 00:32:50 +08:00
section . item . append ( TableCell ( title : " login " , content : login ) )
}
2017-03-31 00:28:37 -07:00
section . item . append ( TableCell ( title : " password " , content : password . password ) )
tableData . append ( section )
// a d d i t i o n s e c t i o n
2017-03-03 17:12:25 +08:00
2017-03-05 02:54:36 +08:00
// s h o w o n e t i m e p a s s w o r d
2017-03-24 23:14:44 +08:00
if password . otpType != . none {
if let ( title , otp ) = self . password ? . getOtpStrings ( ) {
2017-03-31 00:28:37 -07:00
section = TableSection ( type : . addition , header : " One Time Password " )
section . item . append ( TableCell ( title : title , content : otp ) )
tableData . append ( section )
2017-04-01 08:59:22 -07:00
oneTimePasswordIndexPath = IndexPath ( row : 0 , section : tableData . count - 1 )
2017-03-03 14:45:16 +08:00
}
}
2017-03-03 17:12:25 +08:00
2017-03-05 02:54:36 +08:00
// s h o w a d d i t i o n a l i n f o r m a t i o n
2017-06-28 00:18:06 +08:00
let filteredAdditionKeys = password . getFilteredAdditions ( )
2017-03-03 17:12:25 +08:00
if filteredAdditionKeys . count > 0 {
2017-03-31 00:28:37 -07:00
section = TableSection ( type : . addition , header : " additions " )
2018-05-05 20:05:03 +02:00
filteredAdditionKeys . forEach ( { field in
section . item . append ( TableCell ( title : field . title , content : field . content ) )
2017-06-28 00:18:06 +08:00
} )
2017-03-31 00:28:37 -07:00
tableData . append ( section )
2017-03-03 17:12:25 +08:00
}
2017-03-31 00:28:37 -07:00
// m i s c s e c t i o n
section = TableSection ( type : . misc )
section . item . append ( TableCell ( title : " Show Raw " ) )
tableData . append ( section )
2017-02-13 01:15:42 +08:00
}
override func prepare ( for segue : UIStoryboardSegue , sender : Any ? ) {
if segue . identifier = = " editPasswordSegue " {
if let controller = segue . destination as ? UINavigationController {
if let editController = controller . viewControllers . first as ? EditPasswordTableViewController {
editController . password = password
}
}
2017-03-31 22:44:30 -07:00
} else if segue . identifier = = " showRawPasswordSegue " {
if let controller = segue . destination as ? UINavigationController {
if let controller = controller . viewControllers . first as ? RawPasswordViewController {
controller . password = password
}
}
2017-02-13 01:15:42 +08:00
}
}
2017-03-22 01:39:26 +08:00
private func updatePasswordImage ( urlString : String ) {
2017-03-15 14:14:42 -07:00
var newUrlString = urlString
if urlString . lowercased ( ) . hasPrefix ( " http:// " ) {
// t r y t o r e p l a c e h t t p u r l t o h t t p s u r l
newUrlString = urlString . replacingOccurrences ( of : " http:// " ,
with : " https:// " ,
options : . caseInsensitive ,
range : urlString . range ( of : " http:// " ) )
} else if urlString . lowercased ( ) . hasPrefix ( " https:// " ) {
// d o n o t h i n g h e r e
} else {
// i f a u r l d o e s n o t s t a r t w i t h h t t p o r h t t p s , t r y t o a d d h t t p s
newUrlString = " https:// \( urlString ) "
}
guard let url = URL ( string : newUrlString ) else {
return
}
2017-02-09 13:17:11 +08:00
do {
2017-02-09 13:33:50 +08:00
try FavIcon . downloadPreferred ( url ) { [ weak self ] result in
2017-02-09 13:17:11 +08:00
switch result {
case . success ( let image ) :
let indexPath = IndexPath ( row : 0 , section : 0 )
2017-02-09 13:33:50 +08:00
self ? . passwordImage = image
self ? . tableView . reloadRows ( at : [ indexPath ] , with : UITableViewRowAnimation . automatic )
2017-02-09 14:41:59 +08:00
let imageData = UIImageJPEGRepresentation ( image , 1 )
2017-02-16 13:24:41 +08:00
if let entity = self ? . passwordEntity {
2017-03-16 22:39:03 -07:00
self ? . passwordStore . updateImage ( passwordEntity : entity , image : imageData )
2017-02-16 13:24:41 +08:00
}
2017-02-09 13:17:11 +08:00
case . failure ( let error ) :
print ( error )
}
2017-02-06 15:03:34 +08:00
}
2017-02-09 13:17:11 +08:00
} catch {
print ( error )
2017-02-06 15:03:34 +08:00
}
2017-02-05 00:35:23 +08:00
}
2017-03-22 01:39:26 +08:00
@objc private func tapMenu ( recognizer : UITapGestureRecognizer ) {
2017-02-05 00:35:23 +08:00
if recognizer . state = = UIGestureRecognizerState . ended {
let tapLocation = recognizer . location ( in : self . tableView )
if let tapIndexPath = self . tableView . indexPathForRow ( at : tapLocation ) {
if let tappedCell = self . tableView . cellForRow ( at : tapIndexPath ) as ? LabelTableViewCell {
tappedCell . becomeFirstResponder ( )
let menuController = UIMenuController . shared
2017-02-06 11:55:27 +08:00
let revealItem = UIMenuItem ( title : " Reveal " , action : #selector ( LabelTableViewCell . revealPassword ( _ : ) ) )
let concealItem = UIMenuItem ( title : " Conceal " , action : #selector ( LabelTableViewCell . concealPassword ( _ : ) ) )
2017-03-22 01:39:26 +08:00
let nextHOTPItem = UIMenuItem ( title : " Next Password " , action : #selector ( LabelTableViewCell . getNextHOTP ( _ : ) ) )
2017-02-08 17:55:18 +08:00
let openURLItem = UIMenuItem ( title : " Copy Password & Open Link " , action : #selector ( LabelTableViewCell . openLink ( _ : ) ) )
2017-03-22 01:39:26 +08:00
menuController . menuItems = [ revealItem , concealItem , nextHOTPItem , openURLItem ]
2017-02-05 00:35:23 +08:00
menuController . setTargetRect ( tappedCell . contentLabel . frame , in : tappedCell . contentLabel . superview ! )
menuController . setMenuVisible ( true , animated : true )
}
}
}
2017-02-04 20:38:40 +08:00
}
2017-04-01 08:36:47 -07:00
func gestureRecognizer ( _ gestureRecognizer : UIGestureRecognizer , shouldReceive touch : UITouch ) -> Bool {
if touch . view ! . isKind ( of : UIButton . classForCoder ( ) ) {
return false
}
return true
}
2017-03-31 22:44:30 -07:00
@IBAction func back ( segue : UIStoryboardSegue ) {
}
2017-02-08 17:55:18 +08:00
2017-03-22 01:39:26 +08:00
func getNextHOTP ( ) {
guard password != nil , passwordEntity != nil , password ? . otpType = = . hotp else {
DispatchQueue . main . async {
Utils . alert ( title : " Error " , message : " Get next password of a non-HOTP entry. " , controller : self , completion : nil )
}
return ;
}
2017-04-09 02:54:05 +08:00
// c o p y H O T P t o p a s t e b o a r d ( w i l l u p d a t e c o u n t e r )
if let plainPassword = password ! . getNextHotp ( ) {
2017-07-27 23:56:24 +08:00
SecurePasteboard . shared . copy ( textToCopy : plainPassword )
2017-03-22 01:39:26 +08:00
}
// c o m m i t t h e c h a n g e o f H O T P c o u n t e r
2017-04-25 13:01:17 -07:00
if password ! . changed != 0 {
do {
self . passwordEntity = try self . passwordStore . edit ( passwordEntity : self . passwordEntity ! , password : self . password ! )
} catch {
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-03-22 01:39:26 +08:00
}
2017-04-25 13:01:17 -07:00
SVProgressHUD . showSuccess ( withStatus : " Password Copied \n Counter Updated " )
SVProgressHUD . dismiss ( withDelay : 1 )
2017-03-22 01:39:26 +08:00
}
}
func openLink ( ) {
2018-06-23 20:42:56 +02:00
var urlString = self . password ? . urlString ? ? " "
2017-10-10 23:24:44 -07:00
if ! urlString . lowercased ( ) . starts ( with : " https:// " ) && ! urlString . lowercased ( ) . starts ( with : " http:// " ) {
urlString = " http:// \( urlString ) "
}
guard let url = URL ( string : urlString ) else {
2017-03-22 01:39:26 +08:00
DispatchQueue . main . async {
Utils . alert ( title : " Error " , message : " Cannot find a valid URL " , controller : self , completion : nil )
}
return ;
}
2017-07-27 23:56:24 +08:00
SecurePasteboard . shared . copy ( textToCopy : password ? . password )
2017-03-22 01:39:26 +08:00
UIApplication . shared . open ( url , options : [ : ] , completionHandler : nil )
}
2017-02-02 21:04:31 +08:00
override func numberOfSections ( in tableView : UITableView ) -> Int {
2017-02-09 15:47:42 +08:00
return tableData . count
2017-02-02 21:04:31 +08:00
}
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
2017-02-09 15:47:42 +08:00
return tableData [ section ] . item . count
2017-02-02 21:04:31 +08:00
}
override func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell {
2017-02-06 20:48:20 +08:00
let sectionIndex = indexPath . section
let rowIndex = indexPath . row
2017-03-31 00:28:37 -07:00
let tableDataItem = tableData [ sectionIndex ] . item [ rowIndex ]
switch ( tableData [ sectionIndex ] . type ) {
case . name :
2017-02-06 20:48:20 +08:00
let cell = tableView . dequeueReusableCell ( withIdentifier : " passwordDetailTitleTableViewCell " , for : indexPath ) as ! PasswordDetailTitleTableViewCell
2017-02-09 13:17:11 +08:00
cell . passwordImageImageView . image = passwordImage ? ? # imageLiteral ( resourceName : " PasswordImagePlaceHolder " )
2018-11-10 22:38:12 -08:00
let passwordName = passwordEntity ! . getName ( )
if passwordEntity ! . synced = = false {
cell . nameLabel . text = " \( passwordName ) ↻ "
} else {
cell . nameLabel . text = passwordName
2017-02-19 00:55:13 +08:00
}
2017-04-23 10:03:09 -07:00
cell . categoryLabel . text = passwordEntity ! . getCategoryText ( )
2017-03-31 22:44:30 -07:00
cell . selectionStyle = . none
2017-02-06 20:48:20 +08:00
return cell
2017-03-31 00:28:37 -07:00
case . main , . addition :
2017-02-06 20:48:20 +08:00
let cell = tableView . dequeueReusableCell ( withIdentifier : " labelCell " , for : indexPath ) as ! LabelTableViewCell
2017-03-31 00:28:37 -07:00
let titleData = tableDataItem . title
let contentData = tableDataItem . content
2017-03-22 01:39:26 +08:00
cell . delegatePasswordTableView = self
2017-02-06 20:48:20 +08:00
cell . cellData = LabelTableViewCellData ( title : titleData , content : contentData )
2017-03-31 22:44:30 -07:00
cell . selectionStyle = . none
2017-02-06 20:48:20 +08:00
return cell
2017-03-31 00:28:37 -07:00
case . misc :
let cell = UITableViewCell ( )
cell . textLabel ? . text = tableDataItem . title
2017-03-31 22:44:30 -07:00
cell . selectionStyle = . default
2017-03-31 00:28:37 -07:00
return cell
2017-02-06 20:48:20 +08:00
}
2017-02-02 21:04:31 +08:00
}
2017-02-04 20:38:40 +08:00
override func tableView ( _ tableView : UITableView , titleForHeaderInSection section : Int ) -> String ? {
2017-03-31 00:28:37 -07:00
return tableData [ section ] . header
2017-02-04 20:38:40 +08:00
}
2017-02-27 08:54:51 +08:00
override func tableView ( _ tableView : UITableView , viewForFooterInSection section : Int ) -> UIView ? {
if section = = tableData . count - 1 {
let view = UIView ( )
2017-02-27 15:21:25 +08:00
let footerLabel = UILabel ( frame : CGRect ( x : 15 , y : 15 , width : tableView . frame . width , height : 60 ) )
2017-02-27 08:54:51 +08:00
footerLabel . numberOfLines = 0
footerLabel . font = UIFont . preferredFont ( forTextStyle : . footnote )
2017-02-27 17:37:53 +08:00
footerLabel . textColor = UIColor . gray
2018-11-10 22:38:12 -08:00
let dateString = self . passwordStore . getLatestUpdateInfo ( filename : password ! . url . path )
2017-03-02 00:06:27 +08:00
footerLabel . text = " Last Updated: \( dateString ) "
2017-02-27 08:54:51 +08:00
view . addSubview ( footerLabel )
return view
}
return nil
}
2017-02-03 18:02:40 +08:00
override func tableView ( _ tableView : UITableView , performAction action : Selector , forRowAt indexPath : IndexPath , withSender sender : Any ? ) {
if action = = #selector ( copy ( _ : ) ) {
2017-07-27 23:56:24 +08:00
SecurePasteboard . shared . copy ( textToCopy : tableData [ indexPath . section ] . item [ indexPath . row ] . content )
2017-02-03 18:02:40 +08:00
}
}
override func tableView ( _ tableView : UITableView , canPerformAction action : Selector , forRowAt indexPath : IndexPath , withSender sender : Any ? ) -> Bool {
2017-03-31 22:44:30 -07:00
let section = tableData [ indexPath . section ]
switch ( section . type ) {
case . main , . addition :
return action = = #selector ( UIResponderStandardEditActions . copy ( _ : ) )
default :
return false
}
2017-02-03 18:02:40 +08:00
}
override func tableView ( _ tableView : UITableView , shouldShowMenuForRowAt indexPath : IndexPath ) -> Bool {
return true
}
2017-03-31 22:44:30 -07:00
override func tableView ( _ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) {
let section = tableData [ indexPath . section ]
if section . type = = . misc {
if section . item [ indexPath . row ] . title = = " Show Raw " {
performSegue ( withIdentifier : " showRawPasswordSegue " , sender : self )
}
}
tableView . deselectRow ( at : indexPath , animated : true )
}
2017-02-02 21:04:31 +08:00
}