diff --git a/Signal/src/AppDelegate.h b/Signal/src/AppDelegate.h index a2ceffe5d..915a72dc9 100644 --- a/Signal/src/AppDelegate.h +++ b/Signal/src/AppDelegate.h @@ -10,7 +10,5 @@ extern NSString *const AppDelegateStoryboardMain; @interface AppDelegate : UIResponder -@property (strong, nonatomic) UIWindow *window; -@property (strong, nonatomic) SignalsViewController *signalVC; @end diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index ff438901f..e7e8f9329 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -19,6 +19,7 @@ #import "Release.h" #import "SendExternalFileViewController.h" #import "Signal-Swift.h" +#import "SignalsNavigationController.h" #import "VersionMigrations.h" #import "ViewControllerUtils.h" #import @@ -58,6 +59,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; @implementation AppDelegate +@synthesize window = _window; + - (void)applicationDidEnterBackground:(UIApplication *)application { DDLogWarn(@"%@ applicationDidEnterBackground.", self.tag); @@ -808,7 +811,10 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; DDLogInfo(@"Presenting initial root view controller"); if ([TSAccountManager isRegistered]) { - self.window.rootViewController = [[UIStoryboard main] instantiateInitialViewController]; + SignalsViewController *homeView = [SignalsViewController new]; + SignalsNavigationController *navigationController = + [[SignalsNavigationController alloc] initWithRootViewController:homeView]; + self.window.rootViewController = navigationController; } else { RegistrationViewController *viewController = [RegistrationViewController new]; UINavigationController *navigationController = diff --git a/Signal/src/Storyboard/Main.storyboard b/Signal/src/Storyboard/Main.storyboard index 7f49e10e0..b69a00d4e 100644 --- a/Signal/src/Storyboard/Main.storyboard +++ b/Signal/src/Storyboard/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -12,95 +12,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -149,25 +60,6 @@ - - - - - - - - - - - - - - - - - - - @@ -372,7 +264,6 @@ - diff --git a/Signal/src/ViewControllers/CodeVerificationViewController.m b/Signal/src/ViewControllers/CodeVerificationViewController.m index b50a49cc4..ab919977d 100644 --- a/Signal/src/ViewControllers/CodeVerificationViewController.m +++ b/Signal/src/ViewControllers/CodeVerificationViewController.m @@ -265,18 +265,13 @@ NS_ASSUME_NONNULL_BEGIN dispatch_async(dispatch_get_main_queue(), ^{ [self stopActivityIndicator]; - UIStoryboard *storyboard = [UIStoryboard main]; - UIViewController *viewController = [storyboard instantiateInitialViewController]; - OWSAssert([viewController isKindOfClass:[SignalsNavigationController class]]); - SignalsNavigationController *navigationController = (SignalsNavigationController *)viewController; + SignalsViewController *homeView = [SignalsViewController new]; + homeView.newlyRegisteredUser = YES; + SignalsNavigationController *navigationController = + [[SignalsNavigationController alloc] initWithRootViewController:homeView]; AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate; appDelegate.window.rootViewController = navigationController; OWSAssert([navigationController.topViewController isKindOfClass:[SignalsViewController class]]); - - DDLogDebug(@"%@ notifying signals view controller of new user.", self.tag); - SignalsViewController *signalsViewController - = (SignalsViewController *)navigationController.topViewController; - signalsViewController.newlyRegisteredUser = YES; }); }) .catch(^(NSError *_Nonnull error) { diff --git a/Signal/src/ViewControllers/SignalsViewController.h b/Signal/src/ViewControllers/SignalsViewController.h index a1f13bf9f..3cc126370 100644 --- a/Signal/src/ViewControllers/SignalsViewController.h +++ b/Signal/src/ViewControllers/SignalsViewController.h @@ -7,17 +7,17 @@ #import "Contact.h" #import "TSGroupModel.h" -@interface SignalsViewController - : UIViewController +@interface SignalsViewController : UIViewController -@property (nonatomic, retain) IBOutlet UITableView *tableView; -@property (nonatomic, strong) IBOutlet UILabel *emptyBoxLabel; +// TODO: Remove this property. @property (nonatomic) BOOL newlyRegisteredUser; - (void)presentThread:(TSThread *)thread keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing callOnViewAppearing:(BOOL)callOnViewAppearing; + - (NSNumber *)updateInboxCountLabel; + - (IBAction)composeNew; - (void)presentTopLevelModalViewController:(UIViewController *)viewController diff --git a/Signal/src/ViewControllers/SignalsViewController.m b/Signal/src/ViewControllers/SignalsViewController.m index 2120e2cb4..9311f50f4 100644 --- a/Signal/src/ViewControllers/SignalsViewController.m +++ b/Signal/src/ViewControllers/SignalsViewController.m @@ -29,9 +29,11 @@ #import #define CELL_HEIGHT 72.0f -#define HEADER_HEIGHT 44.0f -@interface SignalsViewController () +@interface SignalsViewController () + +@property (nonatomic) UITableView *tableView; +@property (nonatomic) UILabel *emptyBoxLabel; @property (nonatomic) YapDatabaseConnection *editingDbConnection; @property (nonatomic) YapDatabaseConnection *uiDatabaseConnection; @@ -57,8 +59,10 @@ // Views -@property (weak, nonatomic) IBOutlet ReminderView *missingContactsPermissionView; -@property (weak, nonatomic) IBOutlet NSLayoutConstraint *hideMissingContactsPermissionViewConstraint; +@property (nonatomic) NSLayoutConstraint *hideArchiveReminderViewConstraint; +@property (nonatomic) NSLayoutConstraint *hideMissingContactsPermissionViewConstraint; + +@property (nonatomic) TSThread *lastThread; @end @@ -82,6 +86,8 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder { + OWSFail(@"Do not load this from the storyboard."); + self = [super initWithCoder:aDecoder]; if (!self) { return self; @@ -146,10 +152,76 @@ #pragma mark - View Life Cycle -- (void)awakeFromNib +- (void)loadView { - [super awakeFromNib]; + [super loadView]; + + self.view.backgroundColor = [UIColor whiteColor]; + + // TODO: Remove this. [[Environment getCurrent] setSignalsViewController:self]; + + self.navigationItem.rightBarButtonItem = + [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose + target:self + action:@selector(composeNew)]; + + ReminderView *archiveReminderView = [ReminderView new]; + archiveReminderView.text = NSLocalizedString( + @"INBOX_VIEW_ARCHIVE_MODE_REMINDER", @"Label reminding the user that they are in archive mode."); + __weak SignalsViewController *weakSelf = self; + archiveReminderView.tapAction = ^{ + [weakSelf selectedInbox]; + }; + [self.view addSubview:archiveReminderView]; + [archiveReminderView autoPinWidthToSuperview]; + [archiveReminderView autoPinToTopLayoutGuideOfViewController:self withInset:0]; + self.hideArchiveReminderViewConstraint = [archiveReminderView autoSetDimension:ALDimensionHeight toSize:0]; + self.hideArchiveReminderViewConstraint.priority = UILayoutPriorityRequired; + + ReminderView *missingContactsPermissionView = [ReminderView new]; + missingContactsPermissionView.text = NSLocalizedString(@"INBOX_VIEW_MISSING_CONTACTS_PERMISSION", + @"Multiline label explaining how to show names instead of phone numbers in your inbox"); + missingContactsPermissionView.tapAction = ^{ + [[UIApplication sharedApplication] openSystemSettings]; + }; + [self.view addSubview:missingContactsPermissionView]; + [missingContactsPermissionView autoPinWidthToSuperview]; + [missingContactsPermissionView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:archiveReminderView]; + self.hideMissingContactsPermissionViewConstraint = + [missingContactsPermissionView autoSetDimension:ALDimensionHeight toSize:0]; + self.hideMissingContactsPermissionViewConstraint.priority = UILayoutPriorityRequired; + + self.tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain]; + self.tableView.delegate = self; + self.tableView.dataSource = self; + [self.view addSubview:self.tableView]; + [self.tableView autoPinWidthToSuperview]; + [self.tableView autoPinToBottomLayoutGuideOfViewController:self withInset:0]; + [self.tableView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:missingContactsPermissionView]; + + UILabel *emptyBoxLabel = [UILabel new]; + self.emptyBoxLabel = emptyBoxLabel; + [self.view addSubview:emptyBoxLabel]; + [emptyBoxLabel autoPinWidthToSuperview]; + [emptyBoxLabel autoPinToTopLayoutGuideOfViewController:self withInset:0]; + [emptyBoxLabel autoPinToBottomLayoutGuideOfViewController:self withInset:0]; + + [self updateReminderViews]; +} + +- (void)updateReminderViews +{ + BOOL shouldHideArchiveReminderView = self.viewingThreadsIn != kArchiveState; + BOOL shouldHideMissingContactsPermissionView = !self.shouldShowMissingContactsPermissionView; + if (self.hideArchiveReminderViewConstraint.active == shouldHideArchiveReminderView + && self.hideMissingContactsPermissionViewConstraint.active == shouldHideMissingContactsPermissionView) { + return; + } + self.hideArchiveReminderViewConstraint.active = shouldHideArchiveReminderView; + self.hideMissingContactsPermissionViewConstraint.active = shouldHideMissingContactsPermissionView; + [self.view setNeedsLayout]; + [self.view layoutSubviews]; } - (void)viewDidLoad { @@ -163,7 +235,7 @@ // Create the database connection. [self uiDatabaseConnection]; - [self selectedInbox:self]; + [self selectedInbox]; self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[ NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil), @@ -179,13 +251,6 @@ navigationItem.leftBarButtonItem.accessibilityLabel = NSLocalizedString( @"SETTINGS_BUTTON_ACCESSIBILITY", @"Accessibility hint for the settings button"); - - self.missingContactsPermissionView.text = NSLocalizedString(@"INBOX_VIEW_MISSING_CONTACTS_PERMISSION", - @"Multiline label explaining how to show names instead of phone numbers in your inbox"); - self.missingContactsPermissionView.tapAction = ^{ - [[UIApplication sharedApplication] openSystemSettings]; - }; - if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] && (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) { [self registerForPreviewingWithDelegate:self sourceView:self.tableView]; @@ -241,6 +306,7 @@ MessagesViewController *vc = [MessagesViewController new]; TSThread *thread = [self threadForIndexPath:indexPath]; + self.lastThread = thread; [vc configureForThread:thread keyboardOnViewAppearing:NO callOnViewAppearing:NO]; [vc peekSetup]; @@ -258,7 +324,7 @@ [self.navigationController pushViewController:vc animated:NO]; } -- (IBAction)composeNew +- (void)composeNew { MessageComposeTableViewController *viewController = [MessageComposeTableViewController new]; @@ -279,9 +345,9 @@ - (void)swappedSegmentedControl { if (self.segmentedControl.selectedSegmentIndex == 0) { - [self selectedInbox:nil]; + [self selectedInbox]; } else { - [self selectedArchive:nil]; + [self selectedArchive]; } } @@ -290,7 +356,7 @@ if ([TSThread numberOfKeysInCollection] > 0) { [self.contactsManager requestSystemContactsOnceWithCompletion:^(NSError *_Nullable error) { dispatch_async(dispatch_get_main_queue(), ^{ - self.hideMissingContactsPermissionViewConstraint.active = !self.shouldShowMissingContactsPermissionView; + [self updateReminderViews]; }); }]; } @@ -299,6 +365,25 @@ self.isViewVisible = YES; [self checkIfEmptyView]; + + // When returning to home view, try to ensure that the "last" thread is still + // visible. The threads often change ordering while in conversation view due + // to incoming & outgoing messages. + if (self.lastThread) { + __block NSIndexPath *indexPathOfLastThread = nil; + [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { + indexPathOfLastThread = + [[transaction extension:TSThreadDatabaseViewExtensionName] indexPathForKey:self.lastThread.uniqueId + inCollection:[TSThread collection] + withMappings:self.threadMappings]; + }]; + + if (indexPathOfLastThread) { + [self.tableView scrollToRowAtIndexPath:indexPathOfLastThread + atScrollPosition:UITableViewScrollPositionNone + animated:NO]; + } + } } - (void)viewWillDisappear:(BOOL)animated @@ -367,6 +452,7 @@ - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; + if (self.newlyRegisteredUser) { [self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) { [self.experienceUpgradeFinder markAllAsSeenWithTransaction:transaction]; @@ -625,6 +711,7 @@ [mvc configureForThread:thread keyboardOnViewAppearing:keyboardOnViewAppearing callOnViewAppearing:callOnViewAppearing]; + self.lastThread = thread; if (self.presentedViewController) { [self.presentedViewController dismissViewControllerAnimated:YES completion:nil]; @@ -695,14 +782,18 @@ } } -#pragma mark - IBAction +#pragma mark - Groupings -- (IBAction)selectedInbox:(id)sender { +- (void)selectedInbox +{ + self.segmentedControl.selectedSegmentIndex = 0; self.viewingThreadsIn = kInboxState; [self changeToGrouping:TSInboxGroup]; } -- (IBAction)selectedArchive:(id)sender { +- (void)selectedArchive +{ + self.segmentedControl.selectedSegmentIndex = 1; self.viewingThreadsIn = kArchiveState; [self changeToGrouping:TSArchiveGroup]; } @@ -719,6 +810,7 @@ [self updateShouldObserveDBModifications]; [self checkIfEmptyView]; + [self updateReminderViews]; } #pragma mark Database delegates @@ -810,12 +902,6 @@ [self checkIfEmptyView]; } -- (IBAction)unwindSettingsDone:(UIStoryboardSegue *)segue { -} - -- (IBAction)unwindMessagesView:(UIStoryboardSegue *)segue { -} - - (void)checkIfEmptyView { [_tableView setHidden:NO]; [_emptyBoxLabel setHidden:NO]; diff --git a/Signal/src/network/PushManager.m b/Signal/src/network/PushManager.m index f14ba2e82..24508a3dd 100644 --- a/Signal/src/network/PushManager.m +++ b/Signal/src/network/PushManager.m @@ -155,7 +155,6 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe success:^{ // TODO do we really want to mark them all as read? [self markAllInThreadAsRead:notification.userInfo completionHandler:completionHandler]; - [[[[Environment getCurrent] signalsViewController] tableView] reloadData]; } failure:^(NSError *error) { // TODO Surface the specific error in the notification? diff --git a/Signal/src/views/ReminderView.swift b/Signal/src/views/ReminderView.swift index dc48fd02d..906459006 100644 --- a/Signal/src/views/ReminderView.swift +++ b/Signal/src/views/ReminderView.swift @@ -51,10 +51,10 @@ class ReminderView: UIView { self.backgroundColor = UIColor.ows_reminderYellow() self.clipsToBounds = true - let container = UIView() - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:))) - container.addGestureRecognizer(tapGesture) + self.addGestureRecognizer(tapGesture) + + let container = UIView() self.addSubview(container) container.autoPinWidthToSuperview(withMargin: 16) diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index c8072fb2f..58228ee9a 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -643,6 +643,9 @@ /* Call setup status label */ "IN_CALL_TERMINATED" = "Call Ended."; +/* Label reminding the user that they are in archive mode. */ +"INBOX_VIEW_ARCHIVE_MODE_REMINDER" = "You are viewing your archived messages. Tap to return to your Inbox."; + /* Multiline label explaining how to show names instead of phone numbers in your inbox */ "INBOX_VIEW_MISSING_CONTACTS_PERMISSION" = "To see the names of your contacts, update your system settings to allow contact access.";