@ -162,6 +162,7 @@ typedef enum : NSUInteger {
@ property ( nonatomic ) NSCache * cellMediaCache ;
@ property ( nonatomic ) NSCache * cellMediaCache ;
@ property ( nonatomic ) LKConversationTitleView * headerView ;
@ property ( nonatomic ) LKConversationTitleView * headerView ;
@ property ( nonatomic , nullable ) UIView * bannerView ;
@ property ( nonatomic , nullable ) UIView * bannerView ;
@ property ( nonatomic , nullable ) UIView * restoreSessionBannerView ;
@ property ( nonatomic , nullable ) OWSDisappearingMessagesConfiguration * disappearingMessagesConfiguration ;
@ property ( nonatomic , nullable ) OWSDisappearingMessagesConfiguration * disappearingMessagesConfiguration ;
/ / Back Button Unread Count
/ / Back Button Unread Count
@ -261,7 +262,7 @@ typedef enum : NSUInteger {
_recordVoiceNoteAudioActivity = [ [ OWSAudioActivity alloc ] initWithAudioDescription : audioActivityDescription behavior : OWSAudioBehavior_PlayAndRecord ] ;
_recordVoiceNoteAudioActivity = [ [ OWSAudioActivity alloc ] initWithAudioDescription : audioActivityDescription behavior : OWSAudioBehavior_PlayAndRecord ] ;
self . scrollContinuity = kScrollContinuityBottom ;
self . scrollContinuity = kScrollContinuityBottom ;
_currentMentionStartIndex = - 1 ;
_currentMentionStartIndex = - 1 ;
_mentions = [ NSMutableArray new ] ;
_mentions = [ NSMutableArray new ] ;
_oldText = @ "";
_oldText = @ "";
@ -418,6 +419,10 @@ typedef enum : NSUInteger {
selector : @ selector ( handleThreadFriendRequestStatusChangedNotification : )
selector : @ selector ( handleThreadFriendRequestStatusChangedNotification : )
name : NSNotification . threadFriendRequestStatusChanged
name : NSNotification . threadFriendRequestStatusChanged
object : nil ] ;
object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( handleThreadSessionRestoreDevicesChangedNotifiaction : )
name : NSNotification . threadSessionRestoreDevicesChanged
object : nil ] ;
[ [ NSNotificationCenter defaultCenter ] addObserver : self
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( handleCalculatingPoWNotification : )
selector : @ selector ( handleCalculatingPoWNotification : )
name : NSNotification . calculatingPoW
name : NSNotification . calculatingPoW
@ -509,6 +514,17 @@ typedef enum : NSUInteger {
[ self resetContentAndLayout ] ;
[ self resetContentAndLayout ] ;
}
}
- ( void ) handleThreadSessionRestoreDevicesChangedNotifiaction : ( NSNotification * ) notification
{
/ / Check thread
NSString * threadID = ( NSString * ) notification . object ;
if ( ![ threadID isEqualToString : self . thread . uniqueId ] ) { return ; }
/ / Ensure thread instance is up to date
[ self . thread reload ] ;
/ / Update UI
[ self updateSessionRestoreBanner ] ;
}
- ( void ) peekSetup
- ( void ) peekSetup
{
{
_peek = YES ;
_peek = YES ;
@ -547,7 +563,7 @@ typedef enum : NSUInteger {
selector : @ selector ( reloadTimerDidFire )
selector : @ selector ( reloadTimerDidFire )
userInfo : nil
userInfo : nil
repeats : YES ] ;
repeats : YES ] ;
[ LKAPI populateUserHexEncodedPublicKeyCacheIfNeededFor : thread . uniqueId in : nil ] ;
[ LKAPI populateUserHexEncodedPublicKeyCacheIfNeededFor : thread . uniqueId in : nil ] ;
}
}
@ -622,7 +638,7 @@ typedef enum : NSUInteger {
[ super viewDidLoad ] ;
[ super viewDidLoad ] ;
[ self createContents ] ;
[ self createContents ] ;
[ self registerCellClasses ] ;
[ self registerCellClasses ] ;
[ self createConversationScrollButtons ] ;
[ self createConversationScrollButtons ] ;
@ -641,20 +657,20 @@ typedef enum : NSUInteger {
[ self loadDraftInCompose ] ;
[ self loadDraftInCompose ] ;
[ self applyTheme ] ;
[ self applyTheme ] ;
[ self . conversationViewModel viewDidLoad ] ;
[ self . conversationViewModel viewDidLoad ] ;
/ / Loki : Set gradient background
/ / Loki : Set gradient background
self . collectionView . backgroundColor = UIColor . clearColor ;
self . collectionView . backgroundColor = UIColor . clearColor ;
LKGradient * gradient = LKGradients . defaultLokiBackground ;
LKGradient * gradient = LKGradients . defaultLokiBackground ;
self . view . backgroundColor = UIColor . clearColor ;
self . view . backgroundColor = UIColor . clearColor ;
[ self . view setGradient : gradient ] ;
[ self . view setGradient : gradient ] ;
/ / Loki : Set navigation bar background color
/ / Loki : Set navigation bar background color
UINavigationBar * navigationBar = self . navigationController . navigationBar ;
UINavigationBar * navigationBar = self . navigationController . navigationBar ;
[ navigationBar setBackgroundImage : [ UIImage new ] forBarMetrics : UIBarMetricsDefault ] ;
[ navigationBar setBackgroundImage : [ UIImage new ] forBarMetrics : UIBarMetricsDefault ] ;
navigationBar . shadowImage = [ UIImage new ] ;
navigationBar . shadowImage = [ UIImage new ] ;
[ navigationBar setTranslucent : NO ] ;
[ navigationBar setTranslucent : NO ] ;
navigationBar . barTintColor = LKColors . navigationBarBackground ;
navigationBar . barTintColor = LKColors . navigationBarBackground ;
/ / Loki : Set up navigation bar buttons
/ / Loki : Set up navigation bar buttons
UIBarButtonItem * backButton = [ [ UIBarButtonItem alloc ] initWithTitle : NSLocalizedString ( @ "Back ", "") style : UIBarButtonItemStylePlain target : nil action : nil ] ;
UIBarButtonItem * backButton = [ [ UIBarButtonItem alloc ] initWithTitle : NSLocalizedString ( @ "Back ", "") style : UIBarButtonItemStylePlain target : nil action : nil ] ;
backButton . tintColor = LKColors . text ;
backButton . tintColor = LKColors . text ;
@ -662,7 +678,7 @@ typedef enum : NSUInteger {
UIBarButtonItem * settingsButton = [ [ UIBarButtonItem alloc ] initWithImage : [ UIImage imageNamed : @ "Gear "] style : UIBarButtonItemStylePlain target : self action : @ selector ( showConversationSettings ) ] ;
UIBarButtonItem * settingsButton = [ [ UIBarButtonItem alloc ] initWithImage : [ UIImage imageNamed : @ "Gear "] style : UIBarButtonItemStylePlain target : self action : @ selector ( showConversationSettings ) ] ;
settingsButton . tintColor = LKColors . text ;
settingsButton . tintColor = LKColors . text ;
self . navigationItem . rightBarButtonItem = settingsButton ;
self . navigationItem . rightBarButtonItem = settingsButton ;
if ( self . thread . isGroupThread ) {
if ( self . thread . isGroupThread ) {
TSGroupThread * thread = ( TSGroupThread * ) self . thread ;
TSGroupThread * thread = ( TSGroupThread * ) self . thread ;
if ( thread . isRSSFeed ) { return ; }
if ( thread . isRSSFeed ) { return ; }
@ -719,7 +735,7 @@ typedef enum : NSUInteger {
[ self . progressIndicatorView autoPinEdgeToSuperviewEdge : ALEdgeTop ] ;
[ self . progressIndicatorView autoPinEdgeToSuperviewEdge : ALEdgeTop ] ;
[ self . progressIndicatorView autoPinEdgeToSuperviewSafeArea : ALEdgeLeading ] ;
[ self . progressIndicatorView autoPinEdgeToSuperviewSafeArea : ALEdgeLeading ] ;
[ self . progressIndicatorView autoPinEdgeToSuperviewSafeArea : ALEdgeTrailing ] ;
[ self . progressIndicatorView autoPinEdgeToSuperviewSafeArea : ALEdgeTrailing ] ;
[ self . collectionView applyScrollViewInsetsFix ] ;
[ self . collectionView applyScrollViewInsetsFix ] ;
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER ( self , _collectionView ) ;
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER ( self , _collectionView ) ;
@ -728,7 +744,7 @@ typedef enum : NSUInteger {
self . inputToolbar . inputTextViewDelegate = self ;
self . inputToolbar . inputTextViewDelegate = self ;
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER ( self , _inputToolbar ) ;
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER ( self , _inputToolbar ) ;
[ self updateInputToolbar ] ;
[ self updateInputToolbar ] ;
self . loadMoreHeader = [ UILabel new ] ;
self . loadMoreHeader = [ UILabel new ] ;
self . loadMoreHeader . text = NSLocalizedString ( @ "CONVERSATION_VIEW_LOADING_MORE_MESSAGES ", @ "Indicates that the app is loading more messages in this conversation . ") ;
self . loadMoreHeader . text = NSLocalizedString ( @ "CONVERSATION_VIEW_LOADING_MORE_MESSAGES ", @ "Indicates that the app is loading more messages in this conversation . ") ;
self . loadMoreHeader . textColor = [ LKColors . text colorWithAlphaComponent : 0.8 ] ;
self . loadMoreHeader . textColor = [ LKColors . text colorWithAlphaComponent : 0.8 ] ;
@ -835,6 +851,7 @@ typedef enum : NSUInteger {
OWSLogDebug ( @ "viewWillAppear ") ;
OWSLogDebug ( @ "viewWillAppear ") ;
[ self ensureBannerState ] ;
[ self ensureBannerState ] ;
[ self updateSessionRestoreBanner ] ;
[ super viewWillAppear : animated ] ;
[ super viewWillAppear : animated ] ;
@ -992,6 +1009,38 @@ typedef enum : NSUInteger {
return [ result copy ] ;
return [ result copy ] ;
}
}
- ( void ) updateSessionRestoreBanner {
BOOL isContactThread = [ self . thread isKindOfClass : [ TSContactThread class ] ] ;
BOOL shouldRemoveBanner = !isContactThread ;
if ( isContactThread ) {
TSContactThread * thread = ( TSContactThread * ) self . thread ;
if ( thread . sessionRestoreDevices . count > 0 ) {
if ( self . restoreSessionBannerView == nil ) {
LKSessionRestorationView * bannerView = [ [ LKSessionRestorationView alloc ] initWithThread : thread ] ;
[ self . view addSubview : bannerView ] ;
[ bannerView autoPinEdgeToSuperviewEdge : ALEdgeLeft withInset : LKValues . mediumSpacing ] ;
[ bannerView autoPinEdgeToSuperviewEdge : ALEdgeTop withInset : LKValues . largeSpacing ] ;
[ bannerView autoPinEdgeToSuperviewEdge : ALEdgeRight withInset : LKValues . mediumSpacing ] ;
[ self . view layoutSubviews ] ;
self . restoreSessionBannerView = bannerView ;
[ bannerView setOnRestore : ^{
[ self restoreSession ] ;
} ] ;
[ bannerView setOnDismiss : ^{
[ thread removeAllSessionRestoreDevicesWithTransaction : nil ] ;
} ] ;
}
} else {
shouldRemoveBanner = true ;
}
}
if ( shouldRemoveBanner && self . restoreSessionBannerView ) {
[ self . restoreSessionBannerView removeFromSuperview ] ;
self . restoreSessionBannerView = nil ;
}
}
- ( void ) ensureBannerState
- ( void ) ensureBannerState
{
{
/ / This method should be called rarely , so it ' s simplest to discard and
/ / This method should be called rarely , so it ' s simplest to discard and
@ -1163,6 +1212,27 @@ typedef enum : NSUInteger {
} ] ;
} ] ;
}
}
- ( void ) restoreSession {
if ( [ self . thread isKindOfClass : [ TSContactThread class ] ] ) {
OWSMessageSender * messageSender = SSKEnvironment . shared . messageSender ;
TSContactThread * thread = ( TSContactThread * ) self . thread ;
NSArray * devices = thread . sessionRestoreDevices ;
for ( NSString * device in devices ) {
if ( device . length == 0 ) { continue ; }
OWSMessageSend * sessionRestoreMessage = [ messageSender getSessionRestoreMessageForHexEncodedPublicKey : device ] ;
if ( sessionRestoreMessage ) {
dispatch_async ( OWSDispatch . sendingQueue , ^{
[ messageSender sendMessage : sessionRestoreMessage ] ;
} ) ;
}
}
[ [ [ TSInfoMessage alloc ] initWithTimestamp : NSDate . ows_millisecondTimeStamp inThread : thread messageType : TSInfoMessageTypeLokiSessionResetInProgress ] save ] ;
thread . sessionResetState = TSContactThreadSessionResetStateRequestReceived ;
[ thread save ] ;
[ thread removeAllSessionRestoreDevicesWithTransaction : nil ] ;
}
}
- ( void ) noLongerVerifiedBannerViewWasTapped : ( UIGestureRecognizer * ) sender
- ( void ) noLongerVerifiedBannerViewWasTapped : ( UIGestureRecognizer * ) sender
{
{
if ( sender . state == UIGestureRecognizerStateRecognized ) {
if ( sender . state == UIGestureRecognizerStateRecognized ) {
@ -1333,7 +1403,7 @@ typedef enum : NSUInteger {
/ / - Begin presenting another view , e . g . swipe - left for details or swipe - right to go back , but quit part way , so that you remain on the conversation view
/ / - Begin presenting another view , e . g . swipe - left for details or swipe - right to go back , but quit part way , so that you remain on the conversation view
/ / - toolbar will be not be visible unless we reaquire first responder .
/ / - toolbar will be not be visible unless we reaquire first responder .
if ( !self . isFirstResponder ) {
if ( !self . isFirstResponder ) {
/ / We don ' t have to worry about the input toolbar being visible if the inputToolbar . textView is first responder
/ / We don ' t have to worry about the input toolbar being visible if the inputToolbar . textView is first responder
/ / In fact doing so would unnecessarily dismiss the keyboard which is probably not desirable and at least
/ / In fact doing so would unnecessarily dismiss the keyboard which is probably not desirable and at least
/ / a distracting animation .
/ / a distracting animation .
@ -1481,7 +1551,7 @@ typedef enum : NSUInteger {
- ( void ) updateBarButtonItems
- ( void ) updateBarButtonItems
{
{
return ; / / Loki : Re - enable later ?
return ; / / Loki : Re - enable later ?
self . navigationItem . hidesBackButton = NO ;
self . navigationItem . hidesBackButton = NO ;
if ( self . customBackButton ) {
if ( self . customBackButton ) {
self . navigationItem . leftBarButtonItem = self . customBackButton ;
self . navigationItem . leftBarButtonItem = self . customBackButton ;
@ -1508,7 +1578,7 @@ typedef enum : NSUInteger {
UIButton * callButton = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
UIButton * callButton = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
UIImage * image = [ [ UIImage imageNamed : @ "button_phone_white "] imageWithRenderingMode : UIImageRenderingModeAlwaysTemplate ] ;
UIImage * image = [ [ UIImage imageNamed : @ "button_phone_white "] imageWithRenderingMode : UIImageRenderingModeAlwaysTemplate ] ;
[ callButton setImage : image forState : UIControlStateNormal ] ;
[ callButton setImage : image forState : UIControlStateNormal ] ;
if ( OWSWindowManager . sharedManager . hasCall ) {
if ( OWSWindowManager . sharedManager . hasCall ) {
callButton . enabled = NO ;
callButton . enabled = NO ;
callButton . userInteractionEnabled = NO ;
callButton . userInteractionEnabled = NO ;
@ -1520,7 +1590,7 @@ typedef enum : NSUInteger {
}
}
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero ;
UIEdgeInsets imageEdgeInsets = UIEdgeInsetsZero ;
/ / We normally would want to use left and right insets that ensure the button
/ / We normally would want to use left and right insets that ensure the button
/ / is square and the icon is centered . However UINavigationBar doesn ' t offer us
/ / is square and the icon is centered . However UINavigationBar doesn ' t offer us
/ / control over the margins and spacing of its content , and the buttons end up
/ / control over the margins and spacing of its content , and the buttons end up
@ -1604,7 +1674,7 @@ typedef enum : NSUInteger {
isAttachmentButtonHidden = false ;
isAttachmentButtonHidden = false ;
}
}
[ self . inputToolbar setUserInteractionEnabled : isEnabled ] ;
[ self . inputToolbar setUserInteractionEnabled : isEnabled ] ;
NSString * placeholderText = isEnabled ? NSLocalizedString ( @ "Message ", "") : NSLocalizedString ( @ "Pending message request ", "") ;
NSString * placeholderText = isEnabled ? NSLocalizedString ( @ "Message ", "") : NSLocalizedString ( @ "Pending session request ", "") ;
[ self . inputToolbar setPlaceholderText : placeholderText ] ;
[ self . inputToolbar setPlaceholderText : placeholderText ] ;
[ self . inputToolbar setAttachmentButtonHidden : isAttachmentButtonHidden ] ;
[ self . inputToolbar setAttachmentButtonHidden : isAttachmentButtonHidden ] ;
}
}
@ -1873,14 +1943,14 @@ typedef enum : NSUInteger {
/ / Before 2.13 we didn ' t track the recipient id in the identity change error .
/ / Before 2.13 we didn ' t track the recipient id in the identity change error .
OWSLogWarn ( @ "Ignoring tap on legacy nonblocking identity change since it has no signal id ") ;
OWSLogWarn ( @ "Ignoring tap on legacy nonblocking identity change since it has no signal id ") ;
return ;
return ;
} else {
} else {
OWSLogInfo ( @ "Assuming tap on legacy nonblocking identity change corresponds to current contact thread : %@",
OWSLogInfo ( @ "Assuming tap on legacy nonblocking identity change corresponds to current contact thread : %@",
self . thread . contactIdentifier ) ;
self . thread . contactIdentifier ) ;
signalIdParam = self . thread . contactIdentifier ;
signalIdParam = self . thread . contactIdentifier ;
}
}
}
}
NSString * signalId = signalIdParam ;
NSString * signalId = signalIdParam ;
[ self showFingerprintWithRecipientId : signalId ] ;
[ self showFingerprintWithRecipientId : signalId ] ;
@ -2408,7 +2478,7 @@ typedef enum : NSUInteger {
self . audioAttachmentPlayer =
self . audioAttachmentPlayer =
[ [ OWSAudioPlayer alloc ] initWithMediaUrl : attachmentStream . originalMediaURL audioBehavior : OWSAudioBehavior_AudioMessagePlayback delegate : viewItem ] ;
[ [ OWSAudioPlayer alloc ] initWithMediaUrl : attachmentStream . originalMediaURL audioBehavior : OWSAudioBehavior_AudioMessagePlayback delegate : viewItem ] ;
/ / Associate the player with this media adapter .
/ / Associate the player with this media adapter .
self . audioAttachmentPlayer . owner = viewItem ;
self . audioAttachmentPlayer . owner = viewItem ;
[ self . audioAttachmentPlayer play ] ;
[ self . audioAttachmentPlayer play ] ;
@ -4261,11 +4331,11 @@ typedef enum : NSUInteger {
[ searchBar setPositionAdjustment : UIOffsetMake ( 4 , 0 ) forSearchBarIcon : UISearchBarIconSearch ] ;
[ searchBar setPositionAdjustment : UIOffsetMake ( 4 , 0 ) forSearchBarIcon : UISearchBarIconSearch ] ;
[ searchBar setSearchTextPositionAdjustment : UIOffsetMake ( 2 , 0 ) ] ;
[ searchBar setSearchTextPositionAdjustment : UIOffsetMake ( 2 , 0 ) ] ;
[ searchBar setPositionAdjustment : UIOffsetMake ( - 4 , 0 ) forSearchBarIcon : UISearchBarIconClear ] ;
[ searchBar setPositionAdjustment : UIOffsetMake ( - 4 , 0 ) forSearchBarIcon : UISearchBarIconClear ] ;
/ / Note : setting a searchBar as the titleView causes UIKit to render the navBar
/ / Note : setting a searchBar as the titleView causes UIKit to render the navBar
/ / * slightly * taller ( 44 pt - > 56 pt )
/ / * slightly * taller ( 44 pt - > 56 pt )
self . navigationItem . titleView = searchBar ;
self . navigationItem . titleView = searchBar ;
[ self updateBarButtonItems ] ;
[ self updateBarButtonItems ] ;
/ / Hack so that the ResultsBar stays on the screen when dismissing the search field
/ / Hack so that the ResultsBar stays on the screen when dismissing the search field
@ -4743,7 +4813,7 @@ typedef enum : NSUInteger {
targetContentOffsetForProposedContentOffset : ( CGPoint ) proposedContentOffset
targetContentOffsetForProposedContentOffset : ( CGPoint ) proposedContentOffset
{
{
if ( @ available ( iOS 13 , * ) ) {
if ( @ available ( iOS 13 , * ) ) {
} else {
} else {
if ( self . menuActionsViewController != nil ) {
if ( self . menuActionsViewController != nil ) {
NSValue * _Nullable contentOffset = [ self contentOffsetForMenuActionInteraction ] ;
NSValue * _Nullable contentOffset = [ self contentOffsetForMenuActionInteraction ] ;