//
// C o p y r i g h t ( c ) 2 0 1 8 O p e n W h i s p e r S y s t e m s . A l l r i g h t s r e s e r v e d .
//
import Foundation
@objc
class ConversationSearchViewController : UITableViewController {
var searchResults : ConversationSearchResults = ConversationSearchResults . empty
var uiDatabaseConnection : YapDatabaseConnection {
// T O D O d o w e w a n t t o r e s p o n d t o Y a p D B M o d i f i e d ? M i g h t b e h a r d w h e n t h e r e ' s l o t s o f s e a r c h r e s u l t s , f o r o n l y m a r g i n a l v a l u e
return OWSPrimaryStorage . shared ( ) . uiDatabaseConnection
}
var searcher : ConversationSearcher {
return ConversationSearcher . shared
}
enum SearchSection : Int {
case conversations = 0
case contacts = 1
case messages = 2
}
// MARK: V i e w L i f e c y l e
override func viewDidLoad ( ) {
super . viewDidLoad ( )
self . view . isHidden = true
self . tableView . register ( ChatSearchResultCell . self , forCellReuseIdentifier : ChatSearchResultCell . reuseIdentifier )
}
// MARK: U I T a b l e V i e w D e l e g a t e
override func tableView ( _ tableView : UITableView , numberOfRowsInSection section : Int ) -> Int {
guard let searchSection = SearchSection ( rawValue : section ) else {
owsFail ( " unknown section: \( section ) " )
return 0
}
switch searchSection {
case . conversations :
return searchResults . conversations . count
case . contacts :
return searchResults . contacts . count
case . messages :
return searchResults . messages . count
}
}
class ChatSearchResultCell : UITableViewCell {
static let reuseIdentifier = " ChatSearchResultCell "
func configure ( searchResult : ConversationSearchItem ) {
self . textLabel ! . text = searchResult . thread . name
}
}
override func tableView ( _ tableView : UITableView , cellForRowAt indexPath : IndexPath ) -> UITableViewCell {
guard let searchSection = SearchSection ( rawValue : indexPath . section ) else {
return UITableViewCell ( )
}
switch searchSection {
case . conversations :
guard let cell = tableView . dequeueReusableCell ( withIdentifier : ChatSearchResultCell . reuseIdentifier ) as ? ChatSearchResultCell else {
return UITableViewCell ( )
}
guard let searchResult = self . searchResults . conversations [ safe : indexPath . row ] else {
return UITableViewCell ( )
}
cell . configure ( searchResult : searchResult )
return cell
case . contacts :
// T O D O
return UITableViewCell ( )
case . messages :
// T O D O
return UITableViewCell ( )
}
}
override func numberOfSections ( in tableView : UITableView ) -> Int {
return 3
}
override func tableView ( _ tableView : UITableView , titleForHeaderInSection section : Int ) -> String ? {
guard let searchSection = SearchSection ( rawValue : section ) else {
owsFail ( " unknown section: \( section ) " )
return nil
}
switch searchSection {
case . conversations :
if searchResults . conversations . count > 0 {
return NSLocalizedString ( " SEARCH_SECTION_CONVERSATIONS " , comment : " section header for search results that match existing conversations (either group or contact conversations) " )
} else {
return nil
}
case . contacts :
if searchResults . contacts . count > 0 {
return NSLocalizedString ( " SEARCH_SECTION_CONTACTS " , comment : " section header for search results that match a contact who doesn't have an existing conversation " )
} else {
return nil
}
case . messages :
if searchResults . messages . count > 0 {
return NSLocalizedString ( " SEARCH_SECTION_MESSAGES " , comment : " section header for search results that match a message in a conversation " )
} else {
return nil
}
}
}
/*
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , titleForFooterInSection section : Int ) -> String ?
// E d i t i n g
// I n d i v i d u a l r o w s c a n o p t o u t o f h a v i n g t h e - e d i t i n g p r o p e r t y s e t f o r t h e m . I f n o t i m p l e m e n t e d , a l l r o w s a r e a s s u m e d t o b e e d i t a b l e .
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , canEditRowAt indexPath : IndexPath ) -> Bool
// M o v i n g / r e o r d e r i n g
// A l l o w s t h e r e o r d e r a c c e s s o r y v i e w t o o p t i o n a l l y b e s h o w n f o r a p a r t i c u l a r r o w . B y d e f a u l t , t h e r e o r d e r c o n t r o l w i l l b e s h o w n o n l y i f t h e d a t a s o u r c e i m p l e m e n t s - t a b l e V i e w : m o v e R o w A t I n d e x P a t h : t o I n d e x P a t h :
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , canMoveRowAt indexPath : IndexPath ) -> Bool
// I n d e x
@ available ( iOS 2.0 , * )
optional public func sectionIndexTitles ( for tableView : UITableView ) -> [ String ] ? // r e t u r n l i s t o f s e c t i o n t i t l e s t o d i s p l a y i n s e c t i o n i n d e x v i e w ( e . g . " A B C D . . . Z # " )
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , sectionForSectionIndexTitle title : String , at index : Int ) -> Int // t e l l t a b l e w h i c h s e c t i o n c o r r e s p o n d s t o s e c t i o n t i t l e / i n d e x ( e . g . " B " , 1 ) )
// D a t a m a n i p u l a t i o n - i n s e r t a n d d e l e t e s u p p o r t
// A f t e r a r o w h a s t h e m i n u s o r p l u s b u t t o n i n v o k e d ( b a s e d o n t h e U I T a b l e V i e w C e l l E d i t i n g S t y l e f o r t h e c e l l ) , t h e d a t a S o u r c e m u s t c o m m i t t h e c h a n g e
// N o t c a l l e d f o r e d i t a c t i o n s u s i n g U I T a b l e V i e w R o w A c t i o n - t h e a c t i o n ' s h a n d l e r w i l l b e i n v o k e d i n s t e a d
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , commit editingStyle : UITableViewCellEditingStyle , forRowAt indexPath : IndexPath )
// D a t a m a n i p u l a t i o n - r e o r d e r / m o v i n g s u p p o r t
@ available ( iOS 2.0 , * )
optional public func tableView ( _ tableView : UITableView , moveRowAt sourceIndexPath : IndexPath , to destinationIndexPath : IndexPath )
*/
}
extension ConversationSearchViewController : UISearchBarDelegate {
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r S h o u l d B e g i n E d i t i n g ( _ s e a r c h B a r : U I S e a r c h B a r ) - > B o o l / / r e t u r n N O t o n o t b e c o m e f i r s t r e s p o n d e r
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r T e x t D i d B e g i n E d i t i n g ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n t e x t s t a r t s e d i t i n g
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r S h o u l d E n d E d i t i n g ( _ s e a r c h B a r : U I S e a r c h B a r ) - > B o o l / / r e t u r n N O t o n o t r e s i g n f i r s t r e s p o n d e r
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r T e x t D i d E n d E d i t i n g ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n t e x t e n d s e d i t i n g
//
public func searchBar ( _ searchBar : UISearchBar , textDidChange searchText : String ) {
guard searchText . stripped . count > 0 else {
self . searchResults = ConversationSearchResults . empty
self . view . isHidden = true
return
}
self . view . isHidden = false
self . uiDatabaseConnection . read { transaction in
self . searchResults = self . searcher . results ( searchText : searchText , transaction : transaction )
}
// TODO: m o r e p e r f o m a n t w a y t o d o . . .
self . tableView . reloadData ( )
}
//
// @ a v a i l a b l e ( i O S 3 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r ( _ s e a r c h B a r : U I S e a r c h B a r , s h o u l d C h a n g e T e x t I n r a n g e : N S R a n g e , r e p l a c e m e n t T e x t t e x t : S t r i n g ) - > B o o l / / c a l l e d b e f o r e t e x t c h a n g e s
//
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r S e a r c h B u t t o n C l i c k e d ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n k e y b o a r d s e a r c h b u t t o n p r e s s e d
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r B o o k m a r k B u t t o n C l i c k e d ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n b o o k m a r k b u t t o n p r e s s e d
//
// @ a v a i l a b l e ( i O S 2 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r C a n c e l B u t t o n C l i c k e d ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n c a n c e l b u t t o n p r e s s e d
//
// @ a v a i l a b l e ( i O S 3 . 2 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r R e s u l t s L i s t B u t t o n C l i c k e d ( _ s e a r c h B a r : U I S e a r c h B a r ) / / c a l l e d w h e n s e a r c h r e s u l t s b u t t o n p r e s s e d
//
//
// @ a v a i l a b l e ( i O S 3 . 0 , * )
// o p t i o n a l p u b l i c f u n c s e a r c h B a r ( _ s e a r c h B a r : U I S e a r c h B a r , s e l e c t e d S c o p e B u t t o n I n d e x D i d C h a n g e s e l e c t e d S c o p e : I n t )
}