Merge branch 'charlesmchen/archivedConversations'

pull/1/head
Matthew Chen 7 years ago
commit 2c1e633914

@ -144,6 +144,23 @@ DEPENDENCIES:
- YapDatabase/SQLCipher (from `https://github.com/signalapp/YapDatabase.git`, branch `release/unencryptedHeaders`) - YapDatabase/SQLCipher (from `https://github.com/signalapp/YapDatabase.git`, branch `release/unencryptedHeaders`)
- YYImage - YYImage
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
- AFNetworking
- ATAppUpdater
- CocoaLumberjack
- JSQSystemSoundPlayer
- libPhoneNumber-iOS
- Mantle
- ProtocolBuffers
- PureLayout
- Reachability
- SAMKeychain
- SSZipArchive
- TwistedOakCollapsingFutures
- UnionFind
- YYImage
EXTERNAL SOURCES: EXTERNAL SOURCES:
AxolotlKit: AxolotlKit:
:git: https://github.com/signalapp/SignalProtocolKit.git :git: https://github.com/signalapp/SignalProtocolKit.git
@ -159,7 +176,7 @@ EXTERNAL SOURCES:
:branch: mkirk/share-compatible :branch: mkirk/share-compatible
:git: https://github.com/signalapp/JSQMessagesViewController.git :git: https://github.com/signalapp/JSQMessagesViewController.git
SignalServiceKit: SignalServiceKit:
:path: . :path: "."
SocketRocket: SocketRocket:
:git: https://github.com/facebook/SocketRocket.git :git: https://github.com/facebook/SocketRocket.git
SQLCipher: SQLCipher:
@ -222,4 +239,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 6a1bafb7c5bedfa4e577580ff12e487cc7111f38 PODFILE CHECKSUM: 6a1bafb7c5bedfa4e577580ff12e487cc7111f38
COCOAPODS: 1.4.0 COCOAPODS: 1.5.0

@ -2412,7 +2412,6 @@
453518641FC635DD00210559 /* Sources */, 453518641FC635DD00210559 /* Sources */,
453518651FC635DD00210559 /* Frameworks */, 453518651FC635DD00210559 /* Frameworks */,
453518661FC635DD00210559 /* Resources */, 453518661FC635DD00210559 /* Resources */,
7B85A55670DC3D49AFBF7359 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -2433,7 +2432,6 @@
4535188E1FC63DBF00210559 /* Frameworks */, 4535188E1FC63DBF00210559 /* Frameworks */,
4535188F1FC63DBF00210559 /* Headers */, 4535188F1FC63DBF00210559 /* Headers */,
453518901FC63DBF00210559 /* Resources */, 453518901FC63DBF00210559 /* Resources */,
6C612B7B27FC78638EB7B113 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -2454,7 +2452,6 @@
D221A086169C9E5E00537ABF /* Frameworks */, D221A086169C9E5E00537ABF /* Frameworks */,
D221A087169C9E5E00537ABF /* Resources */, D221A087169C9E5E00537ABF /* Resources */,
59C9DBA462715B5C999FFB02 /* [CP] Embed Pods Frameworks */, 59C9DBA462715B5C999FFB02 /* [CP] Embed Pods Frameworks */,
3465F381B1856CC06933B3A8 /* [CP] Copy Pods Resources */,
451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */, 451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */,
453518771FC635DD00210559 /* Embed App Extensions */, 453518771FC635DD00210559 /* Embed App Extensions */,
4535189F1FC63DBF00210559 /* Embed Frameworks */, 4535189F1FC63DBF00210559 /* Embed Frameworks */,
@ -2479,7 +2476,6 @@
D221A0A6169C9E5F00537ABF /* Frameworks */, D221A0A6169C9E5F00537ABF /* Frameworks */,
D221A0A7169C9E5F00537ABF /* Resources */, D221A0A7169C9E5F00537ABF /* Resources */,
B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */, B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */,
F76686434770E2BBEBD9665A /* [CP] Copy Pods Resources */,
451DE9FB1DC18D4500810E42 /* [Carthage] Copy Frameworks */, 451DE9FB1DC18D4500810E42 /* [Carthage] Copy Frameworks */,
); );
buildRules = ( buildRules = (
@ -2780,39 +2776,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
3465F381B1856CC06933B3A8 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-resources.sh",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Assets/JSQMessagesAssets.bundle",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Controllers/JSQMessagesViewController.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellIncoming.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesCollectionViewCellOutgoing.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesLoadEarlierHeaderView.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesToolbarContentView.xib",
"${PODS_ROOT}/JSQMessagesViewController/JSQMessagesViewController/Views/JSQMessagesTypingIndicatorFooterView.xib",
"${PODS_ROOT}/SAMKeychain/Support/SAMKeychain.bundle",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/textsecure.cer",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GIAG2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GSR2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GSR4.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR1.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR3.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR4.crt",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Signal/Pods-Signal-resources.sh\"\n";
showEnvVarsInLog = 0;
};
451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */ = { 451DE9EE1DC1546A00810E42 /* [Carthage] Copy Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -2941,47 +2904,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
6C612B7B27FC78638EB7B113 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalMessaging/Pods-SignalMessaging-resources.sh\"\n";
showEnvVarsInLog = 0;
};
7B85A55670DC3D49AFBF7359 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension-resources.sh",
"${PODS_ROOT}/SAMKeychain/Support/SAMKeychain.bundle",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/textsecure.cer",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GIAG2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GSR2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GSR4.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR1.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR2.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR3.crt",
"${PODS_ROOT}/../SignalServiceKit/src/Security/PinningCertificate/GTSR4.crt",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalShareExtension/Pods-SignalShareExtension-resources.sh\"\n";
showEnvVarsInLog = 0;
};
B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */ = { B4E9B04E862FB64FC9A8F79B /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@ -3058,21 +2980,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
F76686434770E2BBEBD9665A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SignalTests/Pods-SignalTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@ -3512,11 +3419,7 @@
"DEBUG=1", "DEBUG=1",
"$(inherited)", "$(inherited)",
); );
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = ( "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "DEBUG=1 $(inherited) SSK_BUILDING_FOR_TESTS=1";
"DEBUG=1",
"$(inherited)",
"SSK_BUILDING_FOR_TESTS=1",
);
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES; GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES; GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "DisclosureIndicatorRTL@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "DisclosureIndicatorRTL@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "DisclosureIndicatorRTL@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

@ -2,7 +2,6 @@
// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
#import "HomeViewController.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
extern NSString *const AppDelegateStoryboardMain; extern NSString *const AppDelegateStoryboardMain;

@ -6,6 +6,7 @@
#import "AppStoreRating.h" #import "AppStoreRating.h"
#import "AppUpdateNag.h" #import "AppUpdateNag.h"
#import "CodeVerificationViewController.h" #import "CodeVerificationViewController.h"
#import "HomeViewController.h"
#import "DebugLogger.h" #import "DebugLogger.h"
#import "MainAppContext.h" #import "MainAppContext.h"
#import "NotificationsManager.h" #import "NotificationsManager.h"
@ -707,14 +708,6 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
DDLogWarn(@"%@ applicationWillResignActive.", self.logTag); DDLogWarn(@"%@ applicationWillResignActive.", self.logTag);
__block OWSBackgroundTask *backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
[AppReadiness runNowOrWhenAppIsReady:^{
if ([TSAccountManager isRegistered]) {
[SignalApp.sharedApp.homeViewController updateInboxCountLabel];
}
backgroundTask = nil;
}];
[DDLog flushLog]; [DDLog flushLog];
} }

@ -13,8 +13,6 @@
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing; callOnViewAppearing:(BOOL)callOnViewAppearing;
- (void)updateInboxCountLabel;
- (void)showNewConversationView; - (void)showNewConversationView;
- (void)presentTopLevelModalViewController:(UIViewController *)viewController - (void)presentTopLevelModalViewController:(UIViewController *)viewController

@ -32,7 +32,12 @@
#import <YapDatabase/YapDatabaseViewChange.h> #import <YapDatabase/YapDatabaseViewChange.h>
#import <YapDatabase/YapDatabaseViewConnection.h> #import <YapDatabase/YapDatabaseViewConnection.h>
typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState }; typedef NS_ENUM(NSInteger, HomeViewMode) {
HomeViewMode_Archive,
HomeViewMode_Inbox,
};
NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversationsReuseIdentifier";
@interface HomeViewController () <UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate> @interface HomeViewController () <UITableViewDelegate, UITableViewDataSource, UIViewControllerPreviewingDelegate>
@ -42,9 +47,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
@property (nonatomic) YapDatabaseConnection *editingDbConnection; @property (nonatomic) YapDatabaseConnection *editingDbConnection;
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection; @property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic) YapDatabaseViewMappings *threadMappings; @property (nonatomic) YapDatabaseViewMappings *threadMappings;
@property (nonatomic) CellState viewingThreadsIn; @property (nonatomic) HomeViewMode homeViewMode;
@property (nonatomic) long inboxCount;
@property (nonatomic) UISegmentedControl *segmentedControl;
@property (nonatomic) id previewingContext; @property (nonatomic) id previewingContext;
@property (nonatomic) NSSet<NSString *> *blockedPhoneNumberSet; @property (nonatomic) NSSet<NSString *> *blockedPhoneNumberSet;
@property (nonatomic, readonly) NSCache<NSString *, ThreadViewModel *> *threadViewModelCache; @property (nonatomic, readonly) NSCache<NSString *, ThreadViewModel *> *threadViewModelCache;
@ -82,6 +85,8 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
return self; return self;
} }
_homeViewMode = HomeViewMode_Inbox;
[self commonInit]; [self commonInit];
return self; return self;
@ -177,30 +182,21 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
// TODO: Remove this. // TODO: Remove this.
[SignalApp.sharedApp setHomeViewController:self]; [SignalApp.sharedApp setHomeViewController:self];
self.navigationItem.rightBarButtonItem = ReminderView *archiveReminderView =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose [ReminderView explanationWithText:NSLocalizedString(@"INBOX_VIEW_ARCHIVE_MODE_REMINDER",
target:self @"Label reminding the user that they are in archive mode.")];
action:@selector(showNewConversationView)];
ReminderView *archiveReminderView = [ReminderView new];
archiveReminderView.text = NSLocalizedString(
@"INBOX_VIEW_ARCHIVE_MODE_REMINDER", @"Label reminding the user that they are in archive mode.");
__weak HomeViewController *weakSelf = self;
archiveReminderView.tapAction = ^{
[weakSelf showInboxGrouping];
};
[self.view addSubview:archiveReminderView]; [self.view addSubview:archiveReminderView];
[archiveReminderView autoPinWidthToSuperview]; [archiveReminderView autoPinWidthToSuperview];
[archiveReminderView autoPinToTopLayoutGuideOfViewController:self withInset:0]; [archiveReminderView autoPinToTopLayoutGuideOfViewController:self withInset:0];
self.hideArchiveReminderViewConstraint = [archiveReminderView autoSetDimension:ALDimensionHeight toSize:0]; self.hideArchiveReminderViewConstraint = [archiveReminderView autoSetDimension:ALDimensionHeight toSize:0];
self.hideArchiveReminderViewConstraint.priority = UILayoutPriorityRequired; self.hideArchiveReminderViewConstraint.priority = UILayoutPriorityRequired;
ReminderView *missingContactsPermissionView = [ReminderView new]; ReminderView *missingContactsPermissionView = [ReminderView
missingContactsPermissionView.text = NSLocalizedString(@"INBOX_VIEW_MISSING_CONTACTS_PERMISSION", nagWithText:NSLocalizedString(@"INBOX_VIEW_MISSING_CONTACTS_PERMISSION",
@"Multi-line label explaining how to show names instead of phone numbers in your inbox"); @"Multi-line label explaining how to show names instead of phone numbers in your inbox")
missingContactsPermissionView.tapAction = ^{ tapAction:^{
[[UIApplication sharedApplication] openSystemSettings]; [[UIApplication sharedApplication] openSystemSettings];
}; }];
[self.view addSubview:missingContactsPermissionView]; [self.view addSubview:missingContactsPermissionView];
[missingContactsPermissionView autoPinWidthToSuperview]; [missingContactsPermissionView autoPinWidthToSuperview];
[missingContactsPermissionView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:archiveReminderView]; [missingContactsPermissionView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:archiveReminderView];
@ -213,6 +209,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
self.tableView.dataSource = self; self.tableView.dataSource = self;
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
[self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:HomeViewCell.cellReuseIdentifier]; [self.tableView registerClass:[HomeViewCell class] forCellReuseIdentifier:HomeViewCell.cellReuseIdentifier];
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kArchivedConversationsReuseIdentifier];
[self.view addSubview:self.tableView]; [self.view addSubview:self.tableView];
[self.tableView autoPinWidthToSuperview]; [self.tableView autoPinWidthToSuperview];
[self.tableView autoPinEdgeToSuperviewEdge:ALEdgeBottom]; [self.tableView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
@ -237,7 +234,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (void)updateReminderViews - (void)updateReminderViews
{ {
BOOL shouldHideArchiveReminderView = self.viewingThreadsIn != kArchiveState; BOOL shouldHideArchiveReminderView = self.homeViewMode != HomeViewMode_Archive;
BOOL shouldHideMissingContactsPermissionView = !self.shouldShowMissingContactsPermissionView; BOOL shouldHideMissingContactsPermissionView = !self.shouldShowMissingContactsPermissionView;
if (self.hideArchiveReminderViewConstraint.active == shouldHideArchiveReminderView if (self.hideArchiveReminderViewConstraint.active == shouldHideArchiveReminderView
&& self.hideMissingContactsPermissionViewConstraint.active == shouldHideMissingContactsPermissionView) { && self.hideMissingContactsPermissionViewConstraint.active == shouldHideMissingContactsPermissionView) {
@ -259,25 +256,28 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
// Create the database connection. // Create the database connection.
[self uiDatabaseConnection]; [self uiDatabaseConnection];
[self showInboxGrouping]; [self updateMappings];
[self checkIfEmptyView];
[self updateReminderViews];
// because this uses the table data source, `tableViewSetup` must happen // because this uses the table data source, `tableViewSetup` must happen
// after mappings have been set up in `showInboxGrouping` // after mappings have been set up in `showInboxGrouping`
[self tableViewSetUp]; [self tableViewSetUp];
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:@[ switch (self.homeViewMode) {
NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil), case HomeViewMode_Inbox:
NSLocalizedString(@"ARCHIVE_NAV_BAR_TITLE", nil) // TODO: Should our app name be translated? Probably not.
]]; self.title = NSLocalizedString(@"HOME_VIEW_TITLE_INBOX", @"Title for the home view's default mode.");
break;
[self.segmentedControl addTarget:self case HomeViewMode_Archive:
action:@selector(swappedSegmentedControl) self.title = NSLocalizedString(@"HOME_VIEW_TITLE_ARCHIVE", @"Title for the home view's 'archive' mode.");
forControlEvents:UIControlEventValueChanged]; break;
UINavigationItem *navigationItem = self.navigationItem; }
navigationItem.titleView = self.segmentedControl; self.navigationItem.backBarButtonItem =
[self.segmentedControl setSelectedSegmentIndex:0]; [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"BACK_BUTTON", @"button text for back button")
navigationItem.leftBarButtonItem.accessibilityLabel style:UIBarButtonItemStylePlain
= NSLocalizedString(@"SETTINGS_BUTTON_ACCESSIBILITY", @"Accessibility hint for the settings button"); target:nil
action:nil];
if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)] if ([self.traitCollection respondsToSelector:@selector(forceTouchCapability)]
&& (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) { && (self.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable)) {
@ -296,6 +296,9 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (void)updateBarButtonItems - (void)updateBarButtonItems
{ {
if (self.homeViewMode != HomeViewMode_Inbox) {
return;
}
const CGFloat kBarButtonSize = 44; const CGFloat kBarButtonSize = 44;
// We use UIButtons with [UIBarButtonItem initWithCustomView:...] instead of // We use UIButtons with [UIBarButtonItem initWithCustomView:...] instead of
// UIBarButtonItem in order to ensure that these buttons are spaced tightly. // UIBarButtonItem in order to ensure that these buttons are spaced tightly.
@ -327,7 +330,15 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
0, 0,
round(image.size.width + imageEdgeInsets.left + imageEdgeInsets.right), round(image.size.width + imageEdgeInsets.left + imageEdgeInsets.right),
round(image.size.height + imageEdgeInsets.top + imageEdgeInsets.bottom)); round(image.size.height + imageEdgeInsets.top + imageEdgeInsets.bottom));
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button]; UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithCustomView:button];
settingsButton.accessibilityLabel
= NSLocalizedString(@"SETTINGS_BUTTON_ACCESSIBILITY", @"Accessibility hint for the settings button");
self.navigationItem.leftBarButtonItem = settingsButton;
self.navigationItem.rightBarButtonItem =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCompose
target:self
action:@selector(showNewConversationView)];
} }
- (void)settingsButtonPressed:(id)sender - (void)settingsButtonPressed:(id)sender
@ -367,6 +378,10 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (void)showNewConversationView - (void)showNewConversationView
{ {
OWSAssertIsOnMainThread();
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
NewContactThreadViewController *viewController = [NewContactThreadViewController new]; NewContactThreadViewController *viewController = [NewContactThreadViewController new];
[self.contactsManager requestSystemContactsOnceWithCompletion:^(NSError *_Nullable error) { [self.contactsManager requestSystemContactsOnceWithCompletion:^(NSError *_Nullable error) {
@ -384,15 +399,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
}]; }];
} }
- (void)swappedSegmentedControl
{
if (self.segmentedControl.selectedSegmentIndex == 0) {
[self showInboxGrouping];
} else {
[self showArchiveGrouping];
}
}
- (void)viewWillAppear:(BOOL)animated - (void)viewWillAppear:(BOOL)animated
{ {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
@ -408,8 +414,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
}]; }];
} }
[self updateInboxCountLabel];
self.isViewVisible = YES; self.isViewVisible = YES;
// When returning to home view, try to ensure that the "last" thread is still // When returning to home view, try to ensure that the "last" thread is still
@ -499,7 +503,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
[self reloadTableViewData]; [self reloadTableViewData];
[self checkIfEmptyView]; [self checkIfEmptyView];
[self updateInboxCountLabel];
// If the user hasn't already granted contact access // If the user hasn't already granted contact access
// we don't want to request until they receive a message. // we don't want to request until they receive a message.
@ -601,7 +604,24 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{ {
return (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)section]; NSInteger result = (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)section];
if (self.homeViewMode == HomeViewMode_Inbox) {
// Add the "archived conversations" row.
result++;
}
return result;
}
- (BOOL)isIndexPathForArchivedConversations:(NSIndexPath *)indexPath
{
if (self.homeViewMode != HomeViewMode_Inbox) {
return NO;
}
if (indexPath.section != 0) {
return NO;
}
NSInteger cellCount = (NSInteger)[self.threadMappings numberOfItemsInSection:(NSUInteger)0];
return indexPath.row == cellCount;
} }
- (ThreadViewModel *)threadViewModelForIndexPath:(NSIndexPath *)indexPath - (ThreadViewModel *)threadViewModelForIndexPath:(NSIndexPath *)indexPath
@ -622,6 +642,15 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
} }
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([self isIndexPathForArchivedConversations:indexPath]) {
return [self cellForArchivedConversationsRow:tableView];
} else {
return [self tableView:tableView cellForConversationAtIndexPath:indexPath];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForConversationAtIndexPath:(NSIndexPath *)indexPath
{ {
HomeViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:HomeViewCell.cellReuseIdentifier]; HomeViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:HomeViewCell.cellReuseIdentifier];
OWSAssert(cell); OWSAssert(cell);
@ -638,6 +667,47 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
return cell; return cell;
} }
- (UITableViewCell *)cellForArchivedConversationsRow:(UITableView *)tableView
{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:kArchivedConversationsReuseIdentifier];
OWSAssert(cell);
for (UIView *subview in cell.contentView.subviews) {
[subview removeFromSuperview];
}
cell.backgroundColor = [UIColor whiteColor];
UIImage *disclosureImage = [UIImage imageNamed:(cell.isRTL ? @"NavBarBack" : @"NavBarBackRTL")];
OWSAssert(disclosureImage);
UIImageView *disclosureImageView = [UIImageView new];
disclosureImageView.image = [disclosureImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
disclosureImageView.tintColor = [UIColor colorWithRGBHex:0xd1d1d6];
[disclosureImageView setContentHuggingHigh];
[disclosureImageView setCompressionResistanceHigh];
UILabel *label = [UILabel new];
label.text = NSLocalizedString(@"HOME_VIEW_ARCHIVED_CONVERSATIONS", @"Label for 'archived conversations' button.");
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont ows_dynamicTypeBodyFont];
label.textColor = [UIColor blackColor];
UIStackView *stackView = [UIStackView new];
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.spacing = 5;
[stackView addArrangedSubview:label];
[stackView addArrangedSubview:disclosureImageView];
[cell.contentView addSubview:stackView];
[stackView autoCenterInSuperview];
// Constrain to cell margins.
[stackView autoPinEdgeToSuperviewMargin:ALEdgeTop relation:NSLayoutRelationGreaterThanOrEqual];
[stackView autoPinEdgeToSuperviewMargin:ALEdgeBottom relation:NSLayoutRelationGreaterThanOrEqual];
[stackView autoPinEdgeToSuperviewMargin:ALEdgeLeading relation:NSLayoutRelationGreaterThanOrEqual];
[stackView autoPinEdgeToSuperviewMargin:ALEdgeTrailing relation:NSLayoutRelationGreaterThanOrEqual];
return cell;
}
- (TSThread *)threadForIndexPath:(NSIndexPath *)indexPath - (TSThread *)threadForIndexPath:(NSIndexPath *)indexPath
{ {
__block TSThread *thread = nil; __block TSThread *thread = nil;
@ -675,6 +745,10 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath - (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if ([self isIndexPathForArchivedConversations:indexPath]) {
return @[];
}
UITableViewRowAction *deleteAction = UITableViewRowAction *deleteAction =
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
title:NSLocalizedString(@"TXT_DELETE_TITLE", nil) title:NSLocalizedString(@"TXT_DELETE_TITLE", nil)
@ -683,7 +757,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
}]; }];
UITableViewRowAction *archiveAction; UITableViewRowAction *archiveAction;
if (self.viewingThreadsIn == kInboxState) { if (self.homeViewMode == HomeViewMode_Inbox) {
archiveAction = [UITableViewRowAction archiveAction = [UITableViewRowAction
rowActionWithStyle:UITableViewRowActionStyleNormal rowActionWithStyle:UITableViewRowActionStyleNormal
title:NSLocalizedString(@"ARCHIVE_ACTION", title:NSLocalizedString(@"ARCHIVE_ACTION",
@ -761,7 +835,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
[thread removeWithTransaction:transaction]; [thread removeWithTransaction:transaction];
}]; }];
_inboxCount -= (self.viewingThreadsIn == kArchiveState) ? 1 : 0;
[self checkIfEmptyView]; [self checkIfEmptyView];
} }
@ -769,31 +842,26 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
{ {
TSThread *thread = [self threadForIndexPath:indexPath]; TSThread *thread = [self threadForIndexPath:indexPath];
BOOL viewingThreadsIn = self.viewingThreadsIn;
[self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { [self.editingDbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
viewingThreadsIn == kInboxState ? [thread archiveThreadWithTransaction:transaction] switch (self.homeViewMode) {
: [thread unarchiveThreadWithTransaction:transaction]; case HomeViewMode_Inbox:
[thread archiveThreadWithTransaction:transaction];
break;
case HomeViewMode_Archive:
[thread unarchiveThreadWithTransaction:transaction];
break;
}
}]; }];
[self checkIfEmptyView]; [self checkIfEmptyView];
} }
- (void)updateInboxCountLabel - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{ {
NSUInteger numberOfItems = [OWSMessageUtils.sharedManager unreadMessagesCount]; if ([self isIndexPathForArchivedConversations:indexPath]) {
NSString *unreadString = NSLocalizedString(@"WHISPER_NAV_BAR_TITLE", nil); [self showArchivedConversations];
return;
if (numberOfItems > 0) {
unreadString = [unreadString stringByAppendingFormat:@" (%@)", [OWSFormat formatInt:(int)numberOfItems]];
} }
[_segmentedControl setTitle:unreadString forSegmentAtIndex:0];
[_segmentedControl sizeToFit];
[_segmentedControl.superview setNeedsLayout];
[_segmentedControl reloadInputViews];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TSThread *thread = [self threadForIndexPath:indexPath]; TSThread *thread = [self threadForIndexPath:indexPath];
[self presentThread:thread keyboardOnViewAppearing:NO callOnViewAppearing:NO]; [self presentThread:thread keyboardOnViewAppearing:NO callOnViewAppearing:NO];
[tableView deselectRowAtIndexPath:indexPath animated:YES]; [tableView deselectRowAtIndexPath:indexPath animated:YES];
@ -898,30 +966,29 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (void)showInboxGrouping - (void)showInboxGrouping
{ {
self.viewingThreadsIn = kInboxState; OWSAssert(self.homeViewMode == HomeViewMode_Archive);
}
- (void)showArchiveGrouping [self.navigationController popToRootViewControllerAnimated:YES];
{
self.viewingThreadsIn = kArchiveState;
} }
- (void)setViewingThreadsIn:(CellState)viewingThreadsIn - (void)showArchivedConversations
{ {
BOOL didChange = _viewingThreadsIn != viewingThreadsIn; OWSAssert(self.homeViewMode == HomeViewMode_Inbox);
_viewingThreadsIn = viewingThreadsIn;
self.segmentedControl.selectedSegmentIndex = (viewingThreadsIn == kInboxState ? 0 : 1); // Push a separate instance of this view using "archive" mode.
if (didChange || !self.threadMappings) { HomeViewController *homeView = [HomeViewController new];
[self updateMappings]; homeView.homeViewMode = HomeViewMode_Archive;
} else { [self.navigationController pushViewController:homeView animated:YES];
[self checkIfEmptyView];
[self updateReminderViews];
}
} }
- (NSString *)currentGrouping - (NSString *)currentGrouping
{ {
return self.viewingThreadsIn == kInboxState ? TSInboxGroup : TSArchiveGroup; switch (self.homeViewMode) {
case HomeViewMode_Inbox:
return TSInboxGroup;
case HomeViewMode_Archive:
return TSArchiveGroup;
}
} }
- (void)updateMappings - (void)updateMappings
@ -986,8 +1053,10 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
if (![[self.uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] hasChangesForGroup:self.currentGrouping if (![[self.uiDatabaseConnection ext:TSThreadDatabaseViewExtensionName] hasChangesForGroup:self.currentGrouping
inNotifications:notifications]) { inNotifications:notifications]) {
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[self.self.threadMappings updateWithTransaction:transaction]; [self.threadMappings updateWithTransaction:transaction];
}]; }];
[self checkIfEmptyView];
return; return;
} }
@ -1011,7 +1080,6 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
// We want this regardless of if we're currently viewing the archive. // We want this regardless of if we're currently viewing the archive.
// So we run it before the early return // So we run it before the early return
[self updateInboxCountLabel];
[self checkIfEmptyView]; [self checkIfEmptyView];
if ([sectionChanges count] == 0 && [rowChanges count] == 0) { if ([sectionChanges count] == 0 && [rowChanges count] == 0) {
@ -1047,13 +1115,11 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
case YapDatabaseViewChangeDelete: { case YapDatabaseViewChangeDelete: {
[self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ] [self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
_inboxCount += (self.viewingThreadsIn == kArchiveState) ? 1 : 0;
break; break;
} }
case YapDatabaseViewChangeInsert: { case YapDatabaseViewChangeInsert: {
[self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ] [self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic]; withRowAnimation:UITableViewRowAnimationAutomatic];
_inboxCount -= (self.viewingThreadsIn == kArchiveState) ? 1 : 0;
break; break;
} }
case YapDatabaseViewChangeMove: { case YapDatabaseViewChangeMove: {
@ -1076,21 +1142,31 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
- (void)checkIfEmptyView - (void)checkIfEmptyView
{ {
[_tableView setHidden:NO]; // We need to consult the db view, not the mapping since the mapping only knows about
[_emptyBoxLabel setHidden:NO]; // the current group.
if (self.viewingThreadsIn == kInboxState && [self.threadMappings numberOfItemsInGroup:TSInboxGroup] == 0) { __block NSUInteger inboxCount;
[self setEmptyBoxText]; __block NSUInteger archiveCount;
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSThreadDatabaseViewExtensionName];
inboxCount = [viewTransaction numberOfItemsInGroup:TSInboxGroup];
archiveCount = [viewTransaction numberOfItemsInGroup:TSArchiveGroup];
}];
if (self.homeViewMode == HomeViewMode_Inbox && inboxCount == 0 && archiveCount == 0) {
[self updateEmptyBoxText];
[_tableView setHidden:YES]; [_tableView setHidden:YES];
} else if (self.viewingThreadsIn == kArchiveState && [_emptyBoxLabel setHidden:NO];
[self.threadMappings numberOfItemsInGroup:TSArchiveGroup] == 0) { } else if (self.homeViewMode == HomeViewMode_Archive && archiveCount == 0) {
[self setEmptyBoxText]; [self updateEmptyBoxText];
[_tableView setHidden:YES]; [_tableView setHidden:YES];
[_emptyBoxLabel setHidden:NO];
} else { } else {
[_emptyBoxLabel setHidden:YES]; [_emptyBoxLabel setHidden:YES];
[_tableView setHidden:NO];
} }
} }
- (void)setEmptyBoxText - (void)updateEmptyBoxText
{ {
_emptyBoxLabel.textColor = [UIColor grayColor]; _emptyBoxLabel.textColor = [UIColor grayColor];
_emptyBoxLabel.font = [UIFont ows_regularFontWithSize:18.f]; _emptyBoxLabel.font = [UIFont ows_regularFontWithSize:18.f];
@ -1100,7 +1176,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
NSString *firstLine = @""; NSString *firstLine = @"";
NSString *secondLine = @""; NSString *secondLine = @"";
if (self.viewingThreadsIn == kInboxState) { if (self.homeViewMode == HomeViewMode_Inbox) {
if ([Environment.preferences getHasSentAMessage]) { if ([Environment.preferences getHasSentAMessage]) {
firstLine = NSLocalizedString(@"EMPTY_INBOX_FIRST_TITLE", @""); firstLine = NSLocalizedString(@"EMPTY_INBOX_FIRST_TITLE", @"");
secondLine = NSLocalizedString(@"EMPTY_INBOX_FIRST_TEXT", @""); secondLine = NSLocalizedString(@"EMPTY_INBOX_FIRST_TEXT", @"");

@ -82,12 +82,12 @@ NS_ASSUME_NONNULL_BEGIN
_nonContactAccountSet = [NSMutableSet set]; _nonContactAccountSet = [NSMutableSet set];
_collation = [UILocalizedIndexedCollation currentCollation]; _collation = [UILocalizedIndexedCollation currentCollation];
ReminderView *contactsPermissionReminderView = [[ReminderView alloc] ReminderView *contactsPermissionReminderView =
initWithText:NSLocalizedString(@"COMPOSE_SCREEN_MISSING_CONTACTS_PERMISSION", [ReminderView nagWithText:NSLocalizedString(@"COMPOSE_SCREEN_MISSING_CONTACTS_PERMISSION",
@"Multi-line label explaining why compose-screen contact picker is empty.") @"Multi-line label explaining why compose-screen contact picker is empty.")
tapAction:^{ tapAction:^{
[[UIApplication sharedApplication] openSystemSettings]; [[UIApplication sharedApplication] openSystemSettings];
}]; }];
[self.view addSubview:contactsPermissionReminderView]; [self.view addSubview:contactsPermissionReminderView];
[contactsPermissionReminderView autoPinWidthToSuperview]; [contactsPermissionReminderView autoPinWidthToSuperview];
[contactsPermissionReminderView autoPinEdgeToSuperviewMargin:ALEdgeTop]; [contactsPermissionReminderView autoPinEdgeToSuperviewMargin:ALEdgeTop];

@ -3,7 +3,6 @@
// //
#import "ShowGroupMembersViewController.h" #import "ShowGroupMembersViewController.h"
#import "HomeViewController.h"
#import "Signal-Swift.h" #import "Signal-Swift.h"
#import "SignalApp.h" #import "SignalApp.h"
#import "ViewControllerUtils.h" #import "ViewControllerUtils.h"

@ -211,9 +211,12 @@
keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing keyboardOnViewAppearing:(BOOL)keyboardOnViewAppearing
callOnViewAppearing:(BOOL)callOnViewAppearing callOnViewAppearing:(BOOL)callOnViewAppearing
{ {
OWSAssertIsOnMainThread();
// At most one. // At most one.
OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing); OWSAssert(!keyboardOnViewAppearing || !callOnViewAppearing);
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
if (!thread) { if (!thread) {
OWSFail(@"%@ Can't present nil thread.", self.logTag); OWSFail(@"%@ Can't present nil thread.", self.logTag);
return; return;

@ -288,7 +288,6 @@ NSString *const Signal_Message_MarkAsRead_Identifier = @"Signal_Message_MarkAsRe
[thread markAllAsReadWithTransaction:transaction]; [thread markAllAsReadWithTransaction:transaction];
} }
completionBlock:^{ completionBlock:^{
[SignalApp.sharedApp.homeViewController updateInboxCountLabel];
[self cancelNotificationsWithThreadId:threadId]; [self cancelNotificationsWithThreadId:threadId];
completionHandler(); completionHandler();

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Open Whisper Systems. All rights reserved. // Copyright (c) 2018 Open Whisper Systems. All rights reserved.
// //
import Foundation import Foundation
@ -9,7 +9,7 @@ class ReminderView: UIView {
let TAG = "[ReminderView]" let TAG = "[ReminderView]"
let label = UILabel() let label = UILabel()
let defaultTapAction = { static let defaultTapAction = {
Logger.debug("[ReminderView] tapped.") Logger.debug("[ReminderView] tapped.")
} }
@ -25,30 +25,51 @@ class ReminderView: UIView {
} }
} }
required init?(coder: NSCoder) { enum ReminderViewMode {
self.tapAction = defaultTapAction // Nags are urgent interactive prompts, bidding for the user's attention.
case nag
super.init(coder: coder) // Explanations are not interactive or urgent.
case explanation
}
let mode: ReminderViewMode
setupSubviews() @available(*, unavailable, message:"use other constructor instead.")
required init?(coder aDecoder: NSCoder) {
fatalError("\(#function) is unimplemented.")
} }
@available(*, unavailable, message:"use other constructor instead.")
override init(frame: CGRect) { override init(frame: CGRect) {
self.tapAction = defaultTapAction fatalError("\(#function) is unimplemented.")
}
super.init(frame: frame) private init(mode: ReminderViewMode,
text: String, tapAction: @escaping () -> Void) {
self.mode = mode
self.tapAction = tapAction
super.init(frame: .zero)
self.text = text
setupSubviews() setupSubviews()
} }
convenience init(text: String, tapAction: @escaping () -> Void) { @objc public class func nag(text: String, tapAction: @escaping () -> Void) -> ReminderView {
self.init(frame: .zero) return ReminderView(mode: .nag, text: text, tapAction: tapAction)
self.text = text }
self.tapAction = tapAction
@objc public class func explanation(text: String) -> ReminderView {
return ReminderView(mode: .explanation, text: text, tapAction: ReminderView.defaultTapAction)
} }
func setupSubviews() { func setupSubviews() {
self.backgroundColor = UIColor.ows_reminderYellow switch (mode) {
case .nag:
self.backgroundColor = UIColor.ows_reminderYellow
case .explanation:
self.backgroundColor = UIColor(rgbHex: 0xf5f5f5)
}
self.clipsToBounds = true self.clipsToBounds = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:))) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:)))
@ -66,19 +87,25 @@ class ReminderView: UIView {
label.numberOfLines = 0 label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping label.lineBreakMode = .byWordWrapping
label.autoPinEdge(toSuperviewEdge: .top) label.autoPinEdge(toSuperviewEdge: .top)
label.autoPinEdge(toSuperviewEdge: .left) label.autoPinLeadingToSuperviewMargin()
label.autoPinEdge(toSuperviewEdge: .bottom) label.autoPinEdge(toSuperviewEdge: .bottom)
label.textColor = UIColor.black.withAlphaComponent(0.9) label.textColor = UIColor.black.withAlphaComponent(0.9)
guard mode == .nag else {
label.autoPinTrailingToSuperviewMargin()
return
}
// Icon // Icon
let iconImage = #imageLiteral(resourceName: "system_disclosure_indicator").withRenderingMode(.alwaysTemplate) let iconName = (self.isRTL() ? "system_disclosure_indicator_rtl" : "system_disclosure_indicator")
let iconImage = UIImage(named: iconName)?.withRenderingMode(.alwaysTemplate)
let iconView = UIImageView(image: iconImage) let iconView = UIImageView(image: iconImage)
iconView.contentMode = .scaleAspectFit iconView.contentMode = .scaleAspectFit
iconView.tintColor = UIColor.black.withAlphaComponent(0.6) iconView.tintColor = UIColor.black.withAlphaComponent(0.6)
container.addSubview(iconView) container.addSubview(iconView)
iconView.autoPinEdge(toSuperviewEdge: .right) iconView.autoPinLeading(toTrailingEdgeOf: label, offset: 28)
iconView.autoPinEdge(.left, to: .right, of: label, withOffset: 28) iconView.autoPinTrailingToSuperviewMargin()
iconView.autoVCenterInSuperview() iconView.autoVCenterInSuperview()
iconView.autoSetDimension(.width, toSize: 13) iconView.autoSetDimension(.width, toSize: 13)
} }

@ -76,9 +76,6 @@
/* Pressing this button moves a thread from the inbox to the archive */ /* Pressing this button moves a thread from the inbox to the archive */
"ARCHIVE_ACTION" = "Archive"; "ARCHIVE_ACTION" = "Archive";
/* No comment provided by engineer. */
"ARCHIVE_NAV_BAR_TITLE" = "Archive";
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"ATTACHMENT" = "Attachment"; "ATTACHMENT" = "Attachment";
@ -869,9 +866,18 @@
/* No comment provided by engineer. */ /* No comment provided by engineer. */
"GROUP_YOU_LEFT" = "You have left the group."; "GROUP_YOU_LEFT" = "You have left the group.";
/* Label for 'archived conversations' button. */
"HOME_VIEW_ARCHIVED_CONVERSATIONS" = "Archived Conversations";
/* A label for conversations with blocked users. */ /* A label for conversations with blocked users. */
"HOME_VIEW_BLOCKED_CONTACT_CONVERSATION" = "Blocked"; "HOME_VIEW_BLOCKED_CONTACT_CONVERSATION" = "Blocked";
/* Title for the home view's 'archive' mode. */
"HOME_VIEW_TITLE_ARCHIVE" = "Archive";
/* Title for the home view's default mode. */
"HOME_VIEW_TITLE_INBOX" = "Signal";
/* Call setup status label */ /* Call setup status label */
"IN_CALL_CONNECTING" = "Connecting…"; "IN_CALL_CONNECTING" = "Connecting…";
@ -888,7 +894,7 @@
"IN_CALL_TERMINATED" = "Call Ended."; "IN_CALL_TERMINATED" = "Call Ended.";
/* Label reminding the user that they are in archive mode. */ /* 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."; "INBOX_VIEW_ARCHIVE_MODE_REMINDER" = "These conversations are archived. They will appear in the inbox if new messages are received.";
/* Multi-line label explaining how to show names instead of phone numbers in your inbox */ /* Multi-line 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."; "INBOX_VIEW_MISSING_CONTACTS_PERMISSION" = "To see the names of your contacts, update your system settings to allow contact access.";
@ -2110,9 +2116,6 @@
/* Activity indicator title, shown upon returning to the device manager, until you complete the provisioning process on desktop */ /* Activity indicator title, shown upon returning to the device manager, until you complete the provisioning process on desktop */
"WAITING_TO_COMPLETE_DEVICE_LINK_TEXT" = "Complete setup on Signal Desktop."; "WAITING_TO_COMPLETE_DEVICE_LINK_TEXT" = "Complete setup on Signal Desktop.";
/* No comment provided by engineer. */
"WHISPER_NAV_BAR_TITLE" = "Inbox";
/* Info Message when you disable disappearing messages */ /* Info Message when you disable disappearing messages */
"YOU_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "You disabled disappearing messages."; "YOU_DISABLED_DISAPPEARING_MESSAGES_CONFIGURATION" = "You disabled disappearing messages.";

@ -3,7 +3,6 @@
// //
#import "ViewControllerUtils.h" #import "ViewControllerUtils.h"
#import "HomeViewController.h"
#import "NSString+OWS.h" #import "NSString+OWS.h"
#import "PhoneNumber.h" #import "PhoneNumber.h"
#import <AVFoundation/AVFoundation.h> #import <AVFoundation/AVFoundation.h>

Loading…
Cancel
Save