From fe9a61117cc035be895892f4d987b8559b0ed14b Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Mon, 23 Apr 2018 13:49:11 -0400 Subject: [PATCH] Rework archived conversations mode of home view. --- .../Contents.json | 23 +++++++ .../DisclosureIndicatorRTL@1x.png | Bin 0 -> 1417 bytes .../DisclosureIndicatorRTL@2x.png | Bin 0 -> 1702 bytes .../DisclosureIndicatorRTL@3x.png | Bin 0 -> 1981 bytes .../HomeView/HomeViewController.m | 46 ++++++++----- .../NewContactThreadViewController.m | 12 ++-- Signal/src/views/ReminderView.swift | 63 +++++++++++++----- .../translations/en.lproj/Localizable.strings | 2 +- 8 files changed, 103 insertions(+), 43 deletions(-) create mode 100644 Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json create mode 100644 Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png create mode 100644 Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png create mode 100644 Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@3x.png diff --git a/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json b/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json new file mode 100644 index 000000000..433f40bea --- /dev/null +++ b/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png b/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce140e4bff056e18e2b7ddc77d2d9524a3ba864 GIT binary patch literal 1417 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9a!3HF~Pw#sVq*&4&eH|GXHuiJ>Nn{1`ISV`@ ziy0UcEkKyjb(&!UP>o7vNJL45ua8x7ey(0(N`6wRUPW#JP&EUCO@$SZnVVXYs8Erc zlUHn2VXFjIVFhG^g!Ppaz)DK8ZIvQ?0~DO|i&7O#^-S~(l1A zfjnEKjFOT9D}DX)@^Za$W4-*MbbUihOG|wNBYh(yU7!lx;>x^|#0uTKVr7USFmqf| zi<65o3raHc^AtelCMM;Vme?vOfh>Xph&xL%(-1c06+^uR^q@XSM&D4+Kp&g7)QU_T z+CVZmwWTD(eN|9elmqrtO0s@xPHJvyUP&=fpCMN3fME;Qh~mhK!~%$A;6Q}<%?9Lh ztDw~4{G3uy5QOGsme?8DfIWmRj0h2kF6aE*f}+&oVxTrVQ>YeXF?9722y5(&49%cA zkVVmT_!ngYy_yJen4KY1J+c_O`bexcAd4dD00q8PKxRd1PJ~M)Fi64vFto7I$0~uY z(K$aSzbLpMF*z0FGO!jTA#~MXYa$WW7{Tz_eiHo1c=IR_T&hl4@sUU}&LhV4`be9Aao}Wnf}uYH6d7rUuCcAQ|VP z)WnkfqLBRj96PXMb3t4MV?A?-PGotgRvUd#K0?Y@kW32}1?E~iE}%|W31G+du0|>c zSSbAVba4!^5L`ONo9mE)i0f6c!Y4^qg%8&K$zQCuK*^%OlTT)ckm)>gj+Q^S zF0fCx$-B3+H*@3l>`1Sbva`0xeD4?B;27i|@?*JF%z>>c5~1b_@60}&;+XKQf$d$& z5yl9v%n;Z6{R;2I8f1eWtIkhJoa1y$`_!G|t}+cfC%D~x@tNaM9^(zg@;wW!B?~0Z zP53iMe$u3`jc$xb@|i_mbeHVSJofKp2lo`^O7CAT^1r%&2)md2@B4f| e*Yku)NtgZkyE9MOCf4VI3P(>@KbLh*2~7YPIMAj5 literal 0 HcmV?d00001 diff --git a/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png b/Signal/Images.xcassets/system_disclosure_indicator_rtl.imageset/DisclosureIndicatorRTL@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a6abf47c383d7bf52f952055156047febfef1c6d GIT binary patch literal 1702 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 e7JZxjX+L9m-qMRFUu??elF{r5}E)F^Y?`S literal 0 HcmV?d00001 diff --git a/Signal/src/ViewControllers/HomeView/HomeViewController.m b/Signal/src/ViewControllers/HomeView/HomeViewController.m index 36a6b5534..cc3a951ed 100644 --- a/Signal/src/ViewControllers/HomeView/HomeViewController.m +++ b/Signal/src/ViewControllers/HomeView/HomeViewController.m @@ -182,25 +182,21 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations // TODO: Remove this. [SignalApp.sharedApp setHomeViewController:self]; - 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]; - }; + ReminderView *archiveReminderView = + [ReminderView explanationWithText:NSLocalizedString(@"INBOX_VIEW_ARCHIVE_MODE_REMINDER", + @"Label reminding the user that they are in archive mode.")]; [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", - @"Multi-line label explaining how to show names instead of phone numbers in your inbox"); - missingContactsPermissionView.tapAction = ^{ - [[UIApplication sharedApplication] openSystemSettings]; - }; + ReminderView *missingContactsPermissionView = [ReminderView + nagWithText:NSLocalizedString(@"INBOX_VIEW_MISSING_CONTACTS_PERMISSION", + @"Multi-line label explaining how to show names instead of phone numbers in your inbox") + tapAction:^{ + [[UIApplication sharedApplication] openSystemSettings]; + }]; [self.view addSubview:missingContactsPermissionView]; [missingContactsPermissionView autoPinWidthToSuperview]; [missingContactsPermissionView autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:archiveReminderView]; @@ -1056,6 +1052,10 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { [self.self.threadMappings updateWithTransaction:transaction]; }]; + [self checkIfEmptyView]; + self.threadMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[ self.currentGrouping ] + view:TSThreadDatabaseViewExtensionName]; + return; } @@ -1141,17 +1141,27 @@ NSString *const kArchivedConversationsReuseIdentifier = @"kArchivedConversations - (void)checkIfEmptyView { - [_tableView setHidden:NO]; - [_emptyBoxLabel setHidden:NO]; - if (self.homeViewMode == HomeViewMode_Inbox && [self.threadMappings numberOfItemsInGroup:TSInboxGroup] == 0) { + // We need to consult the db view, not the mapping since the mapping only knows about + // the current group. + __block NSUInteger inboxCount; + __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 setEmptyBoxText]; [_tableView setHidden:YES]; - } else if (self.homeViewMode == HomeViewMode_Archive && - [self.threadMappings numberOfItemsInGroup:TSArchiveGroup] == 0) { + [_emptyBoxLabel setHidden:NO]; + } else if (self.homeViewMode == HomeViewMode_Archive && archiveCount == 0) { [self setEmptyBoxText]; [_tableView setHidden:YES]; + [_emptyBoxLabel setHidden:NO]; } else { [_emptyBoxLabel setHidden:YES]; + [_tableView setHidden:NO]; } } diff --git a/Signal/src/ViewControllers/NewContactThreadViewController.m b/Signal/src/ViewControllers/NewContactThreadViewController.m index f955ddd7a..8ff55a48b 100644 --- a/Signal/src/ViewControllers/NewContactThreadViewController.m +++ b/Signal/src/ViewControllers/NewContactThreadViewController.m @@ -82,12 +82,12 @@ NS_ASSUME_NONNULL_BEGIN _nonContactAccountSet = [NSMutableSet set]; _collation = [UILocalizedIndexedCollation currentCollation]; - ReminderView *contactsPermissionReminderView = [[ReminderView alloc] - initWithText:NSLocalizedString(@"COMPOSE_SCREEN_MISSING_CONTACTS_PERMISSION", - @"Multi-line label explaining why compose-screen contact picker is empty.") - tapAction:^{ - [[UIApplication sharedApplication] openSystemSettings]; - }]; + ReminderView *contactsPermissionReminderView = + [ReminderView nagWithText:NSLocalizedString(@"COMPOSE_SCREEN_MISSING_CONTACTS_PERMISSION", + @"Multi-line label explaining why compose-screen contact picker is empty.") + tapAction:^{ + [[UIApplication sharedApplication] openSystemSettings]; + }]; [self.view addSubview:contactsPermissionReminderView]; [contactsPermissionReminderView autoPinWidthToSuperview]; [contactsPermissionReminderView autoPinEdgeToSuperviewMargin:ALEdgeTop]; diff --git a/Signal/src/views/ReminderView.swift b/Signal/src/views/ReminderView.swift index 098cd498e..4f515ee46 100644 --- a/Signal/src/views/ReminderView.swift +++ b/Signal/src/views/ReminderView.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. // import Foundation @@ -9,7 +9,7 @@ class ReminderView: UIView { let TAG = "[ReminderView]" let label = UILabel() - let defaultTapAction = { + static let defaultTapAction = { Logger.debug("[ReminderView] tapped.") } @@ -25,30 +25,51 @@ class ReminderView: UIView { } } - required init?(coder: NSCoder) { - self.tapAction = defaultTapAction + enum ReminderViewMode { + // Nags are urgent interactive prompts, bidding for the user's attention. + case nag + // Explanations are not interactive or urgent. + case explanation + } + let mode: ReminderViewMode - super.init(coder: coder) - - 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) { - 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() } - convenience init(text: String, tapAction: @escaping () -> Void) { - self.init(frame: .zero) - self.text = text - self.tapAction = tapAction + @objc public class func nag(text: String, tapAction: @escaping () -> Void) -> ReminderView { + return ReminderView(mode: .nag, text: text, tapAction: tapAction) + } + + @objc public class func explanation(text: String) -> ReminderView { + return ReminderView(mode: .explanation, text: text, tapAction: ReminderView.defaultTapAction) } 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 let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:))) @@ -66,19 +87,25 @@ class ReminderView: UIView { label.numberOfLines = 0 label.lineBreakMode = .byWordWrapping label.autoPinEdge(toSuperviewEdge: .top) - label.autoPinEdge(toSuperviewEdge: .left) + label.autoPinLeadingToSuperviewMargin() label.autoPinEdge(toSuperviewEdge: .bottom) label.textColor = UIColor.black.withAlphaComponent(0.9) + guard mode == .nag else { + label.autoPinTrailingToSuperviewMargin() + return + } + // 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) iconView.contentMode = .scaleAspectFit iconView.tintColor = UIColor.black.withAlphaComponent(0.6) container.addSubview(iconView) - iconView.autoPinEdge(toSuperviewEdge: .right) - iconView.autoPinEdge(.left, to: .right, of: label, withOffset: 28) + iconView.autoPinLeading(toTrailingEdgeOf: label, offset: 28) + iconView.autoPinTrailingToSuperviewMargin() iconView.autoVCenterInSuperview() iconView.autoSetDimension(.width, toSize: 13) } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 539d40f16..0008b922b 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -894,7 +894,7 @@ "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."; +"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 */ "INBOX_VIEW_MISSING_CONTACTS_PERMISSION" = "To see the names of your contacts, update your system settings to allow contact access.";