2017-01-19 21:15:47 +08:00
//
2017-02-03 13:01:41 +08:00
// P a s s w o r d s V i e w C o n t r o l l e r . s w i f t
2017-01-19 21:15:47 +08:00
// p a s s
//
2017-02-03 13:01:41 +08:00
// C r e a t e d b y M i n g s h e n S u n o n 3 / 2 / 2 0 1 7 .
2017-01-19 21:15:47 +08:00
// 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
import SVProgressHUD
2017-02-06 10:55:24 +08:00
import SwiftyUserDefaults
2017-02-07 20:57:06 +08:00
import PasscodeLock
2017-01-19 21:15:47 +08:00
2017-03-02 14:51:40 +08:00
enum PasswordsTableEntryType {
case password , dir
}
struct PasswordsTableEntry {
var title : String
var isDir : Bool
var passwordEntity : PasswordEntity ?
}
2017-03-02 22:55:41 +08:00
class PasswordsViewController : UIViewController , UITableViewDataSource , UITableViewDelegate , UITabBarControllerDelegate {
2017-03-02 14:51:40 +08:00
private var passwordsTableEntries : [ PasswordsTableEntry ] = [ ]
private var filteredPasswordsTableEntries : [ PasswordsTableEntry ] = [ ]
private var parentPasswordEntity : PasswordEntity ? = nil
2017-03-24 21:53:07 +08:00
private let passwordStore = PasswordStore . shared
2017-03-02 22:55:41 +08:00
private var tapTabBarTime : TimeInterval = 0
2017-03-02 14:51:40 +08:00
2017-03-24 21:53:07 +08:00
private var sections : [ ( index : Int , length : Int , title : String ) ] = Array ( )
private var searchActive : Bool = false
private lazy var searchController : UISearchController = {
2017-03-02 16:46:23 +08:00
let uiSearchController = UISearchController ( searchResultsController : nil )
uiSearchController . searchResultsUpdater = self
uiSearchController . dimsBackgroundDuringPresentation = false
uiSearchController . searchBar . isTranslucent = false
uiSearchController . searchBar . backgroundColor = UIColor . gray
uiSearchController . searchBar . sizeToFit ( )
return uiSearchController
} ( )
2017-03-24 21:53:07 +08:00
private lazy var syncControl : UIRefreshControl = {
let syncControl = UIRefreshControl ( )
syncControl . addTarget ( self , action : #selector ( handleRefresh ( _ : ) ) , for : UIControlEvents . valueChanged )
return syncControl
2017-02-04 11:30:57 +08:00
} ( )
2017-03-24 21:53:07 +08:00
private lazy var searchBarView : UIView = {
let uiView = UIView ( frame : CGRect ( x : 0 , y : 64 , width : self . view . bounds . width , height : 44 ) )
2017-03-02 16:46:23 +08:00
uiView . addSubview ( self . searchController . searchBar )
return uiView
} ( )
2017-03-24 21:53:07 +08:00
private lazy var backUIBarButtonItem : UIBarButtonItem = {
2017-03-02 14:51:40 +08:00
let backUIBarButtonItem = UIBarButtonItem ( title : " Back " , style : . plain , target : self , action : #selector ( self . backAction ( _ : ) ) )
return backUIBarButtonItem
} ( )
2017-03-23 22:46:50 -07:00
2017-03-24 21:53:07 +08:00
private lazy var transitionFromRight : CATransition = {
2017-03-23 22:46:50 -07:00
let transition = CATransition ( )
transition . type = kCATransitionPush
transition . timingFunction = CAMediaTimingFunction ( name : kCAMediaTimingFunctionEaseInEaseOut )
transition . fillMode = kCAFillModeForwards
transition . duration = 0.25
transition . subtype = kCATransitionFromRight
return transition
} ( )
2017-03-24 21:53:07 +08:00
private lazy var transitionFromLeft : CATransition = {
2017-03-23 22:46:50 -07:00
let transition = CATransition ( )
transition . type = kCATransitionPush
transition . timingFunction = CAMediaTimingFunction ( name : kCAMediaTimingFunctionEaseInEaseOut )
transition . fillMode = kCAFillModeForwards
transition . duration = 0.25
transition . subtype = kCATransitionFromLeft
return transition
} ( )
2017-02-03 13:01:41 +08:00
@IBOutlet weak var tableView : UITableView !
2017-01-23 13:43:06 +08:00
2017-03-02 21:39:48 +08:00
private func initPasswordsTableEntries ( parent : PasswordEntity ? ) {
2017-03-02 16:46:23 +08:00
passwordsTableEntries . removeAll ( )
filteredPasswordsTableEntries . removeAll ( )
var passwordEntities = [ PasswordEntity ] ( )
if Defaults [ . isShowFolderOn ] {
2017-03-16 22:39:03 -07:00
passwordEntities = self . passwordStore . fetchPasswordEntityCoreData ( parent : parent )
2017-03-02 16:46:23 +08:00
} else {
2017-03-16 22:39:03 -07:00
passwordEntities = self . passwordStore . fetchPasswordEntityCoreData ( withDir : false )
2017-03-02 16:46:23 +08:00
}
passwordsTableEntries = passwordEntities . map {
PasswordsTableEntry ( title : $0 . name ! , isDir : $0 . isDir , passwordEntity : $0 )
}
2017-03-02 21:39:48 +08:00
parentPasswordEntity = parent
2017-03-02 16:46:23 +08:00
}
2017-02-10 22:15:01 +08:00
@IBAction func cancelAddPassword ( segue : UIStoryboardSegue ) {
}
@IBAction func saveAddPassword ( segue : UIStoryboardSegue ) {
if let controller = segue . source as ? AddPasswordTableViewController {
2017-02-11 19:48:47 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
SVProgressHUD . setDefaultStyle ( . light )
SVProgressHUD . show ( withStatus : " Saving " )
DispatchQueue . global ( qos : . userInitiated ) . async {
2017-03-02 17:26:12 +08:00
do {
2017-03-16 22:39:03 -07:00
try self . passwordStore . add ( password : controller . password ! , progressBlock : { progress in
2017-03-02 17:26:12 +08:00
DispatchQueue . main . async {
SVProgressHUD . showProgress ( progress , status : " Encrypting " )
}
} )
2017-02-11 19:48:47 +08:00
DispatchQueue . main . async {
2017-03-29 00:26:41 +08:00
// w i l l t r i g g e r r e l o a d T a b l e V i e w ( ) b y a n o t i f i c a t i o n
2017-03-02 17:26:12 +08:00
SVProgressHUD . showSuccess ( withStatus : " Done " )
SVProgressHUD . dismiss ( withDelay : 1 )
}
} catch {
DispatchQueue . main . async {
2017-03-16 23:12:31 -07:00
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-02-11 19:48:47 +08:00
}
}
}
2017-02-10 22:15:01 +08:00
}
}
2017-03-02 14:51:40 +08:00
2017-03-24 21:53:07 +08:00
private func syncPasswords ( ) {
2017-02-08 01:29:00 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
SVProgressHUD . setDefaultStyle ( . light )
2017-02-04 15:23:14 +08:00
SVProgressHUD . show ( withStatus : " Sync Password Store " )
2017-03-22 19:07:41 -07:00
let numberOfLocalCommits = self . passwordStore . numberOfLocalCommits ( )
2017-02-04 11:35:28 +08:00
DispatchQueue . global ( qos : . userInitiated ) . async { [ unowned self ] in
2017-02-04 14:24:59 +08:00
do {
2017-03-16 22:39:03 -07:00
try self . passwordStore . pullRepository ( transferProgressBlock : { ( git_transfer_progress , stop ) in
2017-02-04 14:24:59 +08:00
DispatchQueue . main . async {
SVProgressHUD . showProgress ( Float ( git_transfer_progress . pointee . received_objects ) / Float ( git_transfer_progress . pointee . total_objects ) , status : " Pull Remote Repository " )
}
} )
2017-03-22 19:07:41 -07:00
if numberOfLocalCommits > 0 {
2017-03-16 22:39:03 -07:00
try self . passwordStore . pushRepository ( transferProgressBlock : { ( current , total , bytes , stop ) in
2017-02-12 13:31:29 +08:00
DispatchQueue . main . async {
SVProgressHUD . showProgress ( Float ( current ) / Float ( total ) , status : " Push Remote Repository " )
}
} )
}
2017-01-23 17:36:10 +08:00
DispatchQueue . main . async {
2017-03-24 21:53:07 +08:00
self . reloadTableView ( parent : nil )
2017-02-17 21:06:28 +08:00
Defaults [ . gitRepositoryPasswordAttempts ] = 0
2017-01-23 17:36:10 +08:00
SVProgressHUD . showSuccess ( withStatus : " Done " )
SVProgressHUD . dismiss ( withDelay : 1 )
}
2017-02-04 14:24:59 +08:00
} catch {
DispatchQueue . main . async {
2017-03-16 23:12:31 -07:00
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-02-04 14:24:59 +08:00
}
2017-01-23 16:29:36 +08:00
}
}
}
2017-03-02 15:58:26 +08:00
2017-01-19 21:15:47 +08:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
2017-03-24 21:53:07 +08:00
2017-03-02 22:55:41 +08:00
tabBarController ! . delegate = self
2017-02-03 13:01:41 +08:00
tableView . delegate = self
tableView . dataSource = self
2017-01-23 12:48:20 +08:00
definesPresentationContext = true
2017-02-03 13:01:41 +08:00
view . addSubview ( searchBarView )
2017-03-24 21:53:07 +08:00
tableView . insertSubview ( syncControl , at : 0 )
2017-02-06 10:55:24 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
2017-03-10 23:07:56 -08:00
tableView . register ( UINib ( nibName : " PasswordWithFolderTableViewCell " , bundle : nil ) , forCellReuseIdentifier : " passwordWithFolderTableViewCell " )
2017-03-24 21:53:07 +08:00
// i n i t i a l i z e t h e p a s s w o r d t a b l e
reloadTableView ( parent : nil )
// 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-03-29 00:26:41 +08:00
NotificationCenter . default . addObserver ( self , selector : #selector ( actOnReloadTableViewRelatedNotification ) , name : . passwordStoreUpdated , object : nil )
2017-03-24 21:53:07 +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-03-29 00:26:41 +08:00
NotificationCenter . default . addObserver ( self , selector : #selector ( actOnReloadTableViewRelatedNotification ) , name : . passwordDisplaySettingChanged , object : nil )
2017-03-24 21:53:07 +08:00
NotificationCenter . default . addObserver ( self , selector : #selector ( actOnSearchNotification ) , name : . passwordSearch , object : nil )
2017-02-02 15:03:34 +08:00
}
2017-02-03 14:20:52 +08:00
override func viewWillAppear ( _ animated : Bool ) {
super . viewWillAppear ( animated )
if let path = tableView . indexPathForSelectedRow {
tableView . deselectRow ( at : path , animated : false )
}
}
2017-02-07 13:23:18 +08:00
override func viewDidLayoutSubviews ( ) {
super . viewDidLayoutSubviews ( )
searchBarView . frame = CGRect ( x : 0 , y : navigationController ! . navigationBar . bounds . size . height + UIApplication . shared . statusBarFrame . height , width : UIScreen . main . bounds . width , height : 44 )
searchController . searchBar . sizeToFit ( )
}
2017-02-03 13:01:41 +08:00
func numberOfSections ( in tableView : UITableView ) -> Int {
2017-02-02 15:03:34 +08:00
return sections . count
}
2017-02-03 13:01:41 +08:00
func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
return sections [ section ] . length
}
func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell {
2017-03-10 23:07:56 -08:00
let longPressGestureRecognizer = UILongPressGestureRecognizer ( target : self , action : #selector ( longPressAction ( _ : ) ) )
longPressGestureRecognizer . minimumPressDuration = 0.6
if Defaults [ . isShowFolderOn ] {
let cell = tableView . dequeueReusableCell ( withIdentifier : " passwordTableViewCell " , for : indexPath )
let entry = getPasswordEntry ( by : indexPath )
if ! entry . isDir {
if entry . passwordEntity ! . synced {
cell . textLabel ? . text = entry . title
} else {
cell . textLabel ? . text = " ↻ \( entry . title ) "
}
cell . addGestureRecognizer ( longPressGestureRecognizer )
cell . accessoryType = . none
cell . detailTextLabel ? . text = " "
2017-03-02 14:51:40 +08:00
} else {
2017-03-10 23:07:56 -08:00
cell . textLabel ? . text = " \( entry . title ) "
cell . accessoryType = . disclosureIndicator
cell . detailTextLabel ? . text = " \( entry . passwordEntity ? . children ? . count ? ? 0 ) "
2017-03-02 14:51:40 +08:00
}
2017-03-10 23:07:56 -08:00
return cell
2017-02-12 01:59:40 +08:00
} else {
2017-03-10 23:07:56 -08:00
let passwordWithFolderCell = tableView . dequeueReusableCell ( withIdentifier : " passwordWithFolderTableViewCell " , for : indexPath ) as ! PasswordWithFolderTableViewCell
let entry = getPasswordEntry ( by : indexPath )
if entry . passwordEntity ! . synced {
passwordWithFolderCell . passwordLabel ? . text = entry . title
} else {
passwordWithFolderCell . passwordLabel ? . text = " ↻ \( entry . title ) "
}
passwordWithFolderCell . folderLabel . text = entry . passwordEntity ? . getCategoryText ( )
passwordWithFolderCell . addGestureRecognizer ( longPressGestureRecognizer )
return passwordWithFolderCell
2017-02-12 01:59:40 +08:00
}
2017-03-10 23:07:56 -08:00
2017-02-03 13:01:41 +08:00
}
2017-03-02 22:10:41 +08:00
private func getPasswordEntry ( by indexPath : IndexPath ) -> PasswordsTableEntry {
2017-03-02 14:51:40 +08:00
var entry : PasswordsTableEntry
let index = sections [ indexPath . section ] . index + indexPath . row
if searchController . isActive && searchController . searchBar . text != " " {
entry = filteredPasswordsTableEntries [ index ]
} else {
entry = passwordsTableEntries [ index ]
}
return entry
}
func tableView ( _ tableView : UITableView , didSelectRowAt indexPath : IndexPath ) {
let entry = getPasswordEntry ( by : indexPath )
if ! entry . isDir {
2017-03-11 21:09:24 -08:00
let segueIdentifier = " showPasswordDetail "
let sender = tableView . cellForRow ( at : indexPath )
if shouldPerformSegue ( withIdentifier : segueIdentifier , sender : sender ) {
performSegue ( withIdentifier : segueIdentifier , sender : sender )
}
2017-03-02 14:51:40 +08:00
} else {
tableView . deselectRow ( at : indexPath , animated : true )
2017-03-02 16:45:52 +08:00
searchController . isActive = false
2017-03-24 21:53:07 +08:00
reloadTableView ( parent : entry . passwordEntity , anim : transitionFromRight )
2017-03-02 14:51:40 +08:00
}
}
func backAction ( _ sender : Any ? ) {
2017-03-02 22:55:41 +08:00
guard Defaults [ . isShowFolderOn ] else { return }
2017-03-24 21:53:07 +08:00
reloadTableView ( parent : parentPasswordEntity ? . parent , anim : transitionFromLeft )
2017-03-02 14:51:40 +08:00
}
2017-02-08 01:29:00 +08:00
func longPressAction ( _ gesture : UILongPressGestureRecognizer ) {
if gesture . state = = UIGestureRecognizerState . began {
let touchPoint = gesture . location ( in : tableView )
if let indexPath = tableView . indexPathForRow ( at : touchPoint ) {
copyToPasteboard ( from : indexPath )
}
}
}
2017-02-03 13:01:41 +08:00
func tableView ( _ tableView : UITableView , titleForHeaderInSection section : Int ) -> String ? {
return sections [ section ] . title
}
func sectionIndexTitles ( for tableView : UITableView ) -> [ String ] ? {
return sections . map { $0 . title }
}
func tableView ( _ tableView : UITableView , sectionForSectionIndexTitle title : String , at index : Int ) -> Int {
return index
}
2017-02-04 11:30:57 +08:00
func tableView ( _ tableView : UITableView , accessoryButtonTappedForRowWith indexPath : IndexPath ) {
2017-02-08 01:29:00 +08:00
copyToPasteboard ( from : indexPath )
}
2017-03-24 21:53:07 +08:00
private func copyToPasteboard ( from indexPath : IndexPath ) {
2017-03-16 22:39:03 -07:00
guard self . passwordStore . privateKey != nil else {
2017-02-16 00:54:42 +08:00
Utils . alert ( title : " Cannot Copy Password " , message : " PGP Key is not set. Please set your PGP Key first. " , controller : self , completion : nil )
2017-02-15 11:26:22 +08:00
return
}
2017-03-02 16:14:24 +08:00
let password = getPasswordEntry ( by : indexPath ) . passwordEntity !
2017-02-08 19:18:10 +08:00
UIImpactFeedbackGenerator ( style : . medium ) . impactOccurred ( )
2017-02-28 12:25:52 +08:00
var passphrase = " "
2017-03-16 22:39:03 -07:00
if Defaults [ . isRememberPassphraseOn ] && self . passwordStore . pgpKeyPassphrase != nil {
passphrase = self . passwordStore . pgpKeyPassphrase !
2017-02-28 12:25:52 +08:00
self . decryptThenCopyPassword ( passwordEntity : password , passphrase : passphrase )
} else {
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 !
self . decryptThenCopyPassword ( passwordEntity : password , passphrase : passphrase )
} ) )
alert . addTextField ( configurationHandler : { ( textField : UITextField ! ) in
textField . text = " "
textField . isSecureTextEntry = true
} )
self . present ( alert , animated : true , completion : nil )
}
}
2017-03-24 21:53:07 +08:00
private func decryptThenCopyPassword ( passwordEntity : PasswordEntity , passphrase : String ) {
2017-02-20 16:07:32 +08:00
SVProgressHUD . setDefaultMaskType ( . black )
2017-02-08 19:18:10 +08:00
SVProgressHUD . setDefaultStyle ( . dark )
SVProgressHUD . show ( withStatus : " Decrypting " )
DispatchQueue . global ( qos : . userInteractive ) . async {
var decryptedPassword : Password ?
do {
2017-02-28 12:25:52 +08:00
decryptedPassword = try passwordEntity . decrypt ( passphrase : passphrase ) !
2017-02-15 11:37:19 +08:00
DispatchQueue . main . async {
2017-02-23 17:56:12 +08:00
Utils . copyToPasteboard ( textToCopy : decryptedPassword ? . password )
2017-03-02 16:14:24 +08:00
SVProgressHUD . showSuccess ( withStatus : " Password copied, and will be cleared in 45 seconds. " )
2017-02-15 11:37:19 +08:00
SVProgressHUD . dismiss ( withDelay : 0.6 )
}
2017-02-08 19:18:10 +08:00
} catch {
print ( error )
2017-02-15 11:37:19 +08:00
DispatchQueue . main . async {
2017-03-16 23:12:31 -07:00
Utils . alert ( title : " Error " , message : error . localizedDescription , controller : self , completion : nil )
2017-02-15 11:37:19 +08:00
}
2017-02-08 19:18:10 +08:00
}
2017-02-06 14:28:57 +08:00
}
2017-02-04 11:30:57 +08:00
}
2017-03-24 21:53:07 +08:00
private func generateSections ( item : [ PasswordsTableEntry ] ) {
2017-02-02 15:03:34 +08:00
sections . removeAll ( )
2017-03-02 14:51:40 +08:00
guard item . count != 0 else {
2017-02-02 15:03:34 +08:00
return
}
var index = 0
for i in 0 . . < item . count {
2017-03-02 14:51:40 +08:00
let title = item [ index ] . title . uppercased ( )
let commonPrefix = item [ i ] . title . commonPrefix ( with : title , options : . caseInsensitive )
2017-02-02 15:03:34 +08:00
if commonPrefix . characters . count = = 0 {
2017-03-02 14:51:40 +08:00
let firstCharacter = title [ title . startIndex ]
2017-02-02 15:03:34 +08:00
let newSection = ( index : index , length : i - index , title : " \( firstCharacter ) " )
sections . append ( newSection )
index = i
}
}
2017-03-02 14:51:40 +08:00
let title = item [ index ] . title . uppercased ( )
let firstCharacter = title [ title . startIndex ]
2017-02-02 15:03:34 +08:00
let newSection = ( index : index , length : item . count - index , title : " \( firstCharacter ) " )
sections . append ( newSection )
2017-01-23 12:48:20 +08:00
}
2017-02-08 12:47:05 +08:00
func actOnSearchNotification ( ) {
searchController . searchBar . becomeFirstResponder ( )
}
2017-02-07 16:45:14 +08:00
2017-02-06 10:55:24 +08:00
override func shouldPerformSegue ( withIdentifier identifier : String , sender : Any ? ) -> Bool {
if identifier = = " showPasswordDetail " {
2017-03-16 22:39:03 -07:00
guard self . passwordStore . privateKey != nil else {
2017-02-16 00:54:42 +08:00
Utils . alert ( title : " Cannot Show Password " , message : " PGP Key is not set. Please set your PGP Key first. " , controller : self , completion : nil )
2017-02-06 10:55:24 +08:00
if let s = sender as ? UITableViewCell {
let selectedIndexPath = tableView . indexPath ( for : s ) !
tableView . deselectRow ( at : selectedIndexPath , animated : true )
}
return false
}
}
return true
}
2017-02-03 13:01:41 +08:00
2017-01-22 01:42:36 +08:00
override func prepare ( for segue : UIStoryboardSegue , sender : Any ? ) {
if segue . identifier = = " showPasswordDetail " {
2017-02-02 21:04:31 +08:00
if let viewController = segue . destination as ? PasswordDetailTableViewController {
2017-02-02 15:03:34 +08:00
let selectedIndexPath = self . tableView . indexPath ( for : sender as ! UITableViewCell ) !
2017-03-02 14:51:40 +08:00
let passwordEntity = getPasswordEntry ( by : selectedIndexPath ) . passwordEntity !
2017-02-06 14:28:57 +08:00
viewController . passwordEntity = passwordEntity
2017-01-22 01:42:36 +08:00
}
}
}
2017-02-04 11:30:57 +08:00
2017-02-03 13:01:41 +08:00
func filterContentForSearchText ( searchText : String , scope : String = " All " ) {
2017-03-02 14:51:40 +08:00
filteredPasswordsTableEntries = passwordsTableEntries . filter { entry in
return entry . title . lowercased ( ) . contains ( searchText . lowercased ( ) )
2017-02-03 13:01:41 +08:00
}
if searchController . isActive && searchController . searchBar . text != " " {
2017-03-02 14:51:40 +08:00
reloadTableView ( data : filteredPasswordsTableEntries )
2017-02-03 13:01:41 +08:00
} else {
2017-03-02 14:51:40 +08:00
reloadTableView ( data : passwordsTableEntries )
2017-02-03 13:01:41 +08:00
}
2017-02-04 11:30:57 +08:00
}
2017-03-24 21:53:07 +08:00
private func reloadTableView ( data : [ PasswordsTableEntry ] , anim : CAAnimation ? = nil ) {
// s e t n a v i g a t i o n i t e m
var numberOfLocalCommitsString = " "
let numberOfLocalCommits = self . passwordStore . numberOfLocalCommits ( )
if numberOfLocalCommits > 0 {
numberOfLocalCommitsString = " ( \( numberOfLocalCommits ) ) "
}
2017-03-02 14:51:40 +08:00
if parentPasswordEntity != nil {
2017-03-24 21:53:07 +08:00
navigationItem . title = " \( parentPasswordEntity ! . name ! ) \( numberOfLocalCommitsString ) "
2017-03-02 14:51:40 +08:00
navigationItem . leftBarButtonItem = backUIBarButtonItem
} else {
2017-03-24 21:53:07 +08:00
navigationItem . title = " Password Store \( numberOfLocalCommitsString ) "
2017-03-02 14:51:40 +08:00
navigationItem . leftBarButtonItem = nil
}
2017-03-24 21:53:07 +08:00
// s e t t h e p a s s w o r d t a b l e
2017-02-04 11:30:57 +08:00
generateSections ( item : data )
2017-03-23 22:46:50 -07:00
if anim != nil {
self . tableView . layer . add ( anim ! , forKey : " UITableViewReloadDataAnimationKey " )
}
2017-02-03 13:01:41 +08:00
tableView . reloadData ( )
2017-03-23 22:46:50 -07:00
self . tableView . layer . removeAnimation ( forKey : " UITableViewReloadDataAnimationKey " )
2017-03-24 21:53:07 +08:00
// s e t t h e s y n c c o n t r o l t i t l e
2017-03-29 00:56:07 +08:00
let atribbutedTitle = " Last Synced: \( Utils . getLastSyncedTimeString ( ) ) "
2017-03-24 21:53:07 +08:00
syncControl . attributedTitle = NSAttributedString ( string : atribbutedTitle )
}
private func reloadTableView ( parent : PasswordEntity ? , anim : CAAnimation ? = nil ) {
initPasswordsTableEntries ( parent : parent )
2017-03-25 00:44:53 +08:00
reloadTableView ( data : passwordsTableEntries , anim : anim )
2017-03-24 21:53:07 +08:00
}
2017-03-29 00:26:41 +08:00
func actOnReloadTableViewRelatedNotification ( ) {
2017-03-24 21:53:07 +08:00
initPasswordsTableEntries ( parent : nil )
2017-03-29 00:26:41 +08:00
DispatchQueue . main . async { [ weak weakSelf = self ] in
guard let strongSelf = weakSelf else { return }
strongSelf . reloadTableView ( data : strongSelf . passwordsTableEntries )
}
2017-02-03 13:01:41 +08:00
}
2017-02-04 11:30:57 +08:00
2017-03-24 21:53:07 +08:00
func handleRefresh ( _ syncControl : UIRefreshControl ) {
2017-02-04 11:47:57 +08:00
syncPasswords ( )
2017-03-24 21:53:07 +08:00
syncControl . endRefreshing ( )
2017-02-04 11:30:57 +08:00
}
2017-03-02 22:55:41 +08:00
func tabBarController ( _ tabBarController : UITabBarController , didSelect viewController : UIViewController ) {
if viewController = = self . navigationController {
let currentTime = Date ( ) . timeIntervalSince1970
let duration = currentTime - self . tapTabBarTime
self . tapTabBarTime = currentTime
if duration < 0.35 {
let topIndexPath = IndexPath ( row : 0 , section : 0 )
tableView . scrollToRow ( at : topIndexPath , at : . bottom , animated : true )
self . tapTabBarTime = 0
return
}
backAction ( self )
}
}
2017-01-19 21:15:47 +08:00
}
2017-01-23 16:29:36 +08:00
2017-02-03 13:01:41 +08:00
extension PasswordsViewController : UISearchResultsUpdating {
2017-01-23 16:29:36 +08:00
func updateSearchResults ( for searchController : UISearchController ) {
filterContentForSearchText ( searchText : searchController . searchBar . text ! )
}
}