mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge branch 'charlesmchen/blocking2'
This commit is contained in:
commit
06ad8733b2
|
@ -55,6 +55,10 @@
|
|||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; };
|
||||
34B3F8941E8DF1710035BE1A /* SignalsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8701E8DF1700035BE1A /* SignalsViewController.m */; };
|
||||
34B3F8991E8DF1B90035BE1A /* TSMessageAdapterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8981E8DF1B90035BE1A /* TSMessageAdapterTest.m */; };
|
||||
34B3F89C1E8DF3270035BE1A /* BlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89B1E8DF3270035BE1A /* BlockListViewController.m */; };
|
||||
34B3F89F1E8DF5490035BE1A /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */; };
|
||||
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */; };
|
||||
34DFCB851E8E04B500053165 /* AddToBlockListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34DFCB841E8E04B500053165 /* AddToBlockListViewController.m */; };
|
||||
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */; };
|
||||
450573FE1E78A06D00615BB4 /* OWS103EnableVideoCalling.m in Sources */ = {isa = PBXBuildFile; fileRef = 450573FD1E78A06D00615BB4 /* OWS103EnableVideoCalling.m */; };
|
||||
4505C2BF1E648EA300CEBF41 /* ExperienceUpgrade.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4505C2BE1E648EA300CEBF41 /* ExperienceUpgrade.swift */; };
|
||||
|
@ -415,6 +419,14 @@
|
|||
34B3F86F1E8DF1700035BE1A /* SignalsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SignalsViewController.h; sourceTree = "<group>"; };
|
||||
34B3F8701E8DF1700035BE1A /* SignalsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SignalsViewController.m; sourceTree = "<group>"; };
|
||||
34B3F8981E8DF1B90035BE1A /* TSMessageAdapterTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageAdapterTest.m; sourceTree = "<group>"; };
|
||||
34B3F89A1E8DF3270035BE1A /* BlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BlockListViewController.h; sourceTree = "<group>"; };
|
||||
34B3F89B1E8DF3270035BE1A /* BlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BlockListViewController.m; sourceTree = "<group>"; };
|
||||
34B3F89D1E8DF5490035BE1A /* OWSTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSTableViewController.h; sourceTree = "<group>"; };
|
||||
34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSTableViewController.m; sourceTree = "<group>"; };
|
||||
34B3F8A01E8EA6040035BE1A /* ViewControllerUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewControllerUtils.h; sourceTree = "<group>"; };
|
||||
34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewControllerUtils.m; sourceTree = "<group>"; };
|
||||
34DFCB831E8E04B400053165 /* AddToBlockListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AddToBlockListViewController.h; sourceTree = "<group>"; };
|
||||
34DFCB841E8E04B500053165 /* AddToBlockListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AddToBlockListViewController.m; sourceTree = "<group>"; };
|
||||
34FD936E1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAnyTouchGestureRecognizer.h; path = views/OWSAnyTouchGestureRecognizer.h; sourceTree = "<group>"; };
|
||||
34FD936F1E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAnyTouchGestureRecognizer.m; path = views/OWSAnyTouchGestureRecognizer.m; sourceTree = "<group>"; };
|
||||
450573FC1E78A06D00615BB4 /* OWS103EnableVideoCalling.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWS103EnableVideoCalling.h; path = Migrations/OWS103EnableVideoCalling.h; sourceTree = "<group>"; };
|
||||
|
@ -804,11 +816,15 @@
|
|||
children = (
|
||||
34B3F8341E8DF1700035BE1A /* AboutTableViewController.h */,
|
||||
34B3F8351E8DF1700035BE1A /* AboutTableViewController.m */,
|
||||
34DFCB831E8E04B400053165 /* AddToBlockListViewController.h */,
|
||||
34DFCB841E8E04B500053165 /* AddToBlockListViewController.m */,
|
||||
34B3F8361E8DF1700035BE1A /* AdvancedSettingsTableViewController.h */,
|
||||
34B3F8371E8DF1700035BE1A /* AdvancedSettingsTableViewController.m */,
|
||||
34B3F8381E8DF1700035BE1A /* AttachmentApprovalViewController.swift */,
|
||||
34B3F8391E8DF1700035BE1A /* AttachmentSharing.h */,
|
||||
34B3F83A1E8DF1700035BE1A /* AttachmentSharing.m */,
|
||||
34B3F89A1E8DF3270035BE1A /* BlockListViewController.h */,
|
||||
34B3F89B1E8DF3270035BE1A /* BlockListViewController.m */,
|
||||
34B3F83B1E8DF1700035BE1A /* CallViewController.swift */,
|
||||
34B3F83C1E8DF1700035BE1A /* CodeVerificationViewController.h */,
|
||||
34B3F83D1E8DF1700035BE1A /* CodeVerificationViewController.m */,
|
||||
|
@ -850,6 +866,8 @@
|
|||
34B3F8611E8DF1700035BE1A /* OWSMessagesToolbarContentView.xib */,
|
||||
34B3F8621E8DF1700035BE1A /* OWSQRCodeScanningViewController.h */,
|
||||
34B3F8631E8DF1700035BE1A /* OWSQRCodeScanningViewController.m */,
|
||||
34B3F89D1E8DF5490035BE1A /* OWSTableViewController.h */,
|
||||
34B3F89E1E8DF5490035BE1A /* OWSTableViewController.m */,
|
||||
34B3F8641E8DF1700035BE1A /* PrivacySettingsTableViewController.h */,
|
||||
34B3F8651E8DF1700035BE1A /* PrivacySettingsTableViewController.m */,
|
||||
34B3F8661E8DF1700035BE1A /* RegistrationViewController.h */,
|
||||
|
@ -863,6 +881,8 @@
|
|||
34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */,
|
||||
34B3F86F1E8DF1700035BE1A /* SignalsViewController.h */,
|
||||
34B3F8701E8DF1700035BE1A /* SignalsViewController.m */,
|
||||
34B3F8A01E8EA6040035BE1A /* ViewControllerUtils.h */,
|
||||
34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */,
|
||||
);
|
||||
path = ViewControllers;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1966,6 +1986,7 @@
|
|||
45C681C61D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */,
|
||||
34B3F8861E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m in Sources */,
|
||||
452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */,
|
||||
34DFCB851E8E04B500053165 /* AddToBlockListViewController.m in Sources */,
|
||||
34B3F8321E8DF11D0035BE1A /* GroupContactsResult.m in Sources */,
|
||||
45855F371D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */,
|
||||
45666EC61D99483D008FE134 /* OWSAvatarBuilder.m in Sources */,
|
||||
|
@ -1974,6 +1995,7 @@
|
|||
76EB068618170B34006006FC /* ContactTableViewCell.m in Sources */,
|
||||
34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */,
|
||||
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
|
||||
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */,
|
||||
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
|
||||
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */,
|
||||
34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */,
|
||||
|
@ -2010,9 +2032,11 @@
|
|||
458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */,
|
||||
451DE9FD1DC1A28200810E42 /* SyncPushTokensJob.swift in Sources */,
|
||||
45666F761D9BFE00008FE134 /* OWS100RemoveTSRecipientsMigration.m in Sources */,
|
||||
34B3F89F1E8DF5490035BE1A /* OWSTableViewController.m in Sources */,
|
||||
FCC81A981A44558300DFEC7D /* UIDevice+TSHardwareVersion.m in Sources */,
|
||||
76EB054018170B33006006FC /* AppDelegate.m in Sources */,
|
||||
341BB7491DB727EE001E2975 /* JSQMediaItem+OWS.m in Sources */,
|
||||
34B3F89C1E8DF3270035BE1A /* BlockListViewController.m in Sources */,
|
||||
45F2B1941D9C9F48000D2C69 /* OWSOutgoingMessageCollectionViewCell.m in Sources */,
|
||||
BFB074C919A5611000F2947C /* ObservableValue.m in Sources */,
|
||||
B68EF9BA1C0B1EBD009C3DCD /* FLAnimatedImage.m in Sources */,
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12118" systemVersion="16E195" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="tuk-0x-yCb">
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="15G1217" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="tuk-0x-yCb">
|
||||
<device id="retina4_7" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12086"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
|
||||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
|
||||
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
||||
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
|
||||
|
@ -678,7 +678,7 @@
|
|||
<objects>
|
||||
<navigationController storyboardIdentifier="UserInitialViewController" automaticallyAdjustsScrollViewInsets="NO" useStoryboardIdentifierAsRestorationIdentifier="YES" id="tuk-0x-yCb" customClass="SignalsNavigationController" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" misplaced="YES" id="VNq-cN-pk9">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="VNq-cN-pk9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="barTintColor" red="0.082137122750282288" green="0.46843802928924561" blue="0.91112053394317627" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
@ -1163,7 +1163,7 @@
|
|||
<objects>
|
||||
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="cZ7-de-SUi" sceneMemberID="viewController">
|
||||
<toolbarItems/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" misplaced="YES" translucent="NO" id="gzw-fh-en2">
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="gzw-fh-en2">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<color key="barTintColor" red="0.082137122750282288" green="0.46843802928924561" blue="0.91112053394317627" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
|
@ -1288,11 +1288,11 @@
|
|||
<viewControllerLayoutGuide type="bottom" id="kH6-9L-pzh"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="P0X-AM-Yjw">
|
||||
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Ukg-om-VX3" userLabel="Group Details">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="100"/>
|
||||
<rect key="frame" x="0.0" y="20" width="375" height="100"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ul8-NY-i4c">
|
||||
<rect key="frame" x="8" y="20" width="60" height="60"/>
|
||||
|
@ -1327,7 +1327,7 @@
|
|||
</constraints>
|
||||
</view>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsMultipleSelection="YES" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="cFo-AT-Srf">
|
||||
<rect key="frame" x="0.0" y="108" width="375" height="495"/>
|
||||
<rect key="frame" x="0.0" y="128" width="375" height="539"/>
|
||||
<color key="backgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.94901960780000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="ekO-kw-iHV" userLabel="Header View">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="40"/>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface AddToBlockListViewController : UIViewController
|
||||
|
||||
@end
|
349
Signal/src/ViewControllers/AddToBlockListViewController.m
Normal file
349
Signal/src/ViewControllers/AddToBlockListViewController.m
Normal file
|
@ -0,0 +1,349 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AddToBlockListViewController.h"
|
||||
#import "CountryCodeViewController.h"
|
||||
#import "PhoneNumber.h"
|
||||
#import "StringUtil.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIUtil.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import "ViewControllerUtils.h"
|
||||
#import <SignalServiceKit/PhoneNumberUtil.h>
|
||||
#import <SignalServiceKit/OWSBlockingManager.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString * const kAddToBlockListViewControllerCellIdentifier = @"kAddToBlockListViewControllerCellIdentifier";
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// TODO: Add a list of contacts to make it easier to block contacts.
|
||||
@interface AddToBlockListViewController () <CountryCodeViewControllerDelegate, UITextFieldDelegate>
|
||||
|
||||
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
|
||||
|
||||
@property (nonatomic) UIButton *countryNameButton;
|
||||
@property (nonatomic) UIButton *countryCodeButton;
|
||||
|
||||
@property (nonatomic) UITextField *phoneNumberTextField;
|
||||
|
||||
@property (nonatomic) UIButton *blockButton;
|
||||
|
||||
@property (nonatomic) NSString *callingCode;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AddToBlockListViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
|
||||
_blockingManager = [OWSBlockingManager sharedManager];
|
||||
|
||||
self.title = NSLocalizedString(@"SETTINGS_ADD_TO_BLOCK_LIST_TITLE", @"");
|
||||
|
||||
[self createViews];
|
||||
|
||||
[self populateDefaultCountryNameAndCode];
|
||||
|
||||
[self addNotificationListeners];
|
||||
}
|
||||
|
||||
- (void)addNotificationListeners
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(blockedPhoneNumbersDidChange:)
|
||||
name:kNSNotificationName_BlockedPhoneNumbersDidChange
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)createViews {
|
||||
// Country Row
|
||||
UIView *countryRow = [self createRowWithHeight:60 previousRow:nil];
|
||||
|
||||
_countryNameButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_countryNameButton.titleLabel.font = [UIFont ows_mediumFontWithSize:16.f];
|
||||
[_countryNameButton setTitleColor:[UIColor blackColor]
|
||||
forState:UIControlStateNormal];
|
||||
[_countryNameButton
|
||||
setTitle:NSLocalizedString(@"REGISTRATION_DEFAULT_COUNTRY_NAME", @"Label for the country code field")
|
||||
forState:UIControlStateNormal];
|
||||
[_countryNameButton addTarget:self
|
||||
action:@selector(showCountryCodeView:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[countryRow addSubview:_countryNameButton];
|
||||
[_countryNameButton autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:20.f];
|
||||
[_countryNameButton autoVCenterInSuperview];
|
||||
|
||||
_countryCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_countryCodeButton.titleLabel.font = [UIFont ows_mediumFontWithSize:16.f];
|
||||
_countryCodeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||||
[_countryCodeButton setTitleColor:[UIColor ows_signalBrandBlueColor]
|
||||
forState:UIControlStateNormal];
|
||||
[_countryCodeButton addTarget:self
|
||||
action:@selector(showCountryCodeView:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
[countryRow addSubview:_countryCodeButton];
|
||||
[_countryCodeButton autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:16.f];
|
||||
[_countryCodeButton autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:_countryNameButton withOffset:0];
|
||||
[_countryCodeButton autoVCenterInSuperview];
|
||||
|
||||
// Border Row
|
||||
UIView *borderRow1 = [self createRowWithHeight:1 previousRow:countryRow];
|
||||
UIColor *borderColor = [UIColor colorWithRed:0.75f green:0.75f blue:0.75f alpha:1.f];
|
||||
borderRow1.backgroundColor = borderColor;
|
||||
|
||||
// Phone Number Row
|
||||
UIView *phoneNumberRow = [self createRowWithHeight:60 previousRow:borderRow1];
|
||||
|
||||
UILabel *phoneNumberLabel = [UILabel new];
|
||||
phoneNumberLabel.font = [UIFont ows_mediumFontWithSize:16.f];
|
||||
phoneNumberLabel.textColor = [UIColor blackColor];
|
||||
phoneNumberLabel.text
|
||||
= NSLocalizedString(@"REGISTRATION_PHONENUMBER_BUTTON", @"Label for the phone number textfield");
|
||||
[phoneNumberRow addSubview:phoneNumberLabel];
|
||||
[phoneNumberLabel autoPinEdgeToSuperviewEdge:ALEdgeLeft withInset:20.f];
|
||||
[phoneNumberLabel autoVCenterInSuperview];
|
||||
|
||||
_phoneNumberTextField = [UITextField new];
|
||||
_phoneNumberTextField.font = [UIFont ows_mediumFontWithSize:16.f];
|
||||
_phoneNumberTextField.textAlignment = NSTextAlignmentRight;
|
||||
_phoneNumberTextField.textColor = [UIColor ows_signalBrandBlueColor];
|
||||
_phoneNumberTextField.placeholder = NSLocalizedString(
|
||||
@"REGISTRATION_ENTERNUMBER_DEFAULT_TEXT", @"Placeholder text for the phone number textfield");
|
||||
_phoneNumberTextField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
_phoneNumberTextField.delegate = self;
|
||||
[_phoneNumberTextField addTarget:self
|
||||
action:@selector(textFieldDidChange:)
|
||||
forControlEvents:UIControlEventEditingChanged];
|
||||
[phoneNumberRow addSubview:_phoneNumberTextField];
|
||||
[_phoneNumberTextField autoPinEdgeToSuperviewEdge:ALEdgeRight withInset:16.f];
|
||||
[_phoneNumberTextField autoPinEdge:ALEdgeLeft toEdge:ALEdgeRight ofView:phoneNumberLabel withOffset:0];
|
||||
[_phoneNumberTextField autoVCenterInSuperview];
|
||||
|
||||
// Border Row
|
||||
UIView *borderRow2 = [self createRowWithHeight:1 previousRow:phoneNumberRow];
|
||||
borderRow2.backgroundColor = borderColor;
|
||||
|
||||
// Block Button Row
|
||||
UIView *blockButtonRow = [self createRowWithHeight:60 previousRow:borderRow2];
|
||||
|
||||
// TODO: Eventually we should make a view factory that will allow us to
|
||||
// create views with consistent appearance across the app and move
|
||||
// towards a "design language."
|
||||
_blockButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_blockButton.titleLabel.font = [UIFont ows_mediumFontWithSize:16.f];
|
||||
[_blockButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
|
||||
[_blockButton setBackgroundColor:[UIColor ows_signalBrandBlueColor]];
|
||||
_blockButton.clipsToBounds = YES;
|
||||
_blockButton.layer.cornerRadius = 3.f;
|
||||
[_blockButton setTitle:NSLocalizedString(
|
||||
@"BLOCK_LIST_VIEW_BLOCK_BUTTON", @"A label for the block button in the block list view")
|
||||
forState:UIControlStateNormal];
|
||||
[_blockButton addTarget:self action:@selector(blockButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[blockButtonRow addSubview:_blockButton];
|
||||
[_blockButton autoCenterInSuperview];
|
||||
[_blockButton autoSetDimension:ALDimensionWidth toSize:160];
|
||||
[_blockButton autoSetDimension:ALDimensionHeight toSize:40];
|
||||
|
||||
[self updateBlockButtonEnabling];
|
||||
}
|
||||
|
||||
- (UIView *)createRowWithHeight:(CGFloat)height previousRow:(nullable UIView *)previousRow
|
||||
{
|
||||
UIView *row = [UIView new];
|
||||
[self.view addSubview:row];
|
||||
[row autoPinWidthToSuperview];
|
||||
if (previousRow) {
|
||||
[row autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:previousRow withOffset:0];
|
||||
} else {
|
||||
[row autoPinToTopLayoutGuideOfViewController:self withInset:0];
|
||||
}
|
||||
[row autoSetDimension:ALDimensionHeight toSize:height];
|
||||
return row;
|
||||
}
|
||||
|
||||
#pragma mark - Country
|
||||
|
||||
- (void)populateDefaultCountryNameAndCode {
|
||||
NSLocale *locale = NSLocale.currentLocale;
|
||||
NSString *countryCode = [locale objectForKey:NSLocaleCountryCode];
|
||||
NSNumber *callingCode = [[PhoneNumberUtil sharedUtil].nbPhoneNumberUtil getCountryCodeForRegion:countryCode];
|
||||
NSString *countryName = [PhoneNumberUtil countryNameFromCountryCode:countryCode];
|
||||
[self updateCountryWithName:countryName
|
||||
callingCode:[NSString stringWithFormat:@"%@%@",
|
||||
COUNTRY_CODE_PREFIX,
|
||||
callingCode]
|
||||
countryCode:countryCode];
|
||||
}
|
||||
|
||||
- (void)updateCountryWithName:(NSString *)countryName
|
||||
callingCode:(NSString *)callingCode
|
||||
countryCode:(NSString *)countryCode {
|
||||
|
||||
_callingCode = callingCode;
|
||||
|
||||
NSString *title = [NSString stringWithFormat:@"%@ (%@)",
|
||||
callingCode,
|
||||
countryCode.uppercaseString];
|
||||
[_countryCodeButton setTitle:title
|
||||
forState:UIControlStateNormal];
|
||||
[_countryCodeButton layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)setCallingCode:(NSString *)callingCode
|
||||
{
|
||||
_callingCode = callingCode;
|
||||
|
||||
[self updateBlockButtonEnabling];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)showCountryCodeView:(id)sender {
|
||||
CountryCodeViewController *countryCodeController = [[UIStoryboard storyboardWithName:@"Registration" bundle:NULL]
|
||||
instantiateViewControllerWithIdentifier:@"CountryCodeViewController"];
|
||||
countryCodeController.delegate = self;
|
||||
countryCodeController.shouldDismissWithoutSegue = YES;
|
||||
UINavigationController *navigationController =
|
||||
[[UINavigationController alloc] initWithRootViewController:countryCodeController];
|
||||
[self presentViewController:navigationController animated:YES completion:[UIUtil modalCompletionBlock]];
|
||||
}
|
||||
|
||||
- (void)blockButtonPressed:(id)sender
|
||||
{
|
||||
[self tryToBlockPhoneNumber];
|
||||
}
|
||||
|
||||
- (void)tryToBlockPhoneNumber
|
||||
{
|
||||
if (![self hasValidPhoneNumber]) {
|
||||
OWSAssert(0);
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *possiblePhoneNumber = [self.callingCode stringByAppendingString:_phoneNumberTextField.text.digitsOnly];
|
||||
PhoneNumber *parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:possiblePhoneNumber];
|
||||
OWSAssert(parsedPhoneNumber);
|
||||
|
||||
[_blockingManager addBlockedPhoneNumber:[parsedPhoneNumber toE164]];
|
||||
|
||||
UIAlertController *controller = [UIAlertController
|
||||
alertControllerWithTitle:NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE",
|
||||
@"The title of the 'phone number blocked' alert in the block view.")
|
||||
message:[NSString
|
||||
stringWithFormat:NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT",
|
||||
@"The message format of the 'phone number blocked' alert in "
|
||||
@"the block view. Embeds {{the blocked phone number}}."),
|
||||
[parsedPhoneNumber toE164]]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
|
||||
_phoneNumberTextField.text = nil;
|
||||
}
|
||||
|
||||
- (void)textFieldDidChange:(id)sender
|
||||
{
|
||||
[self updateBlockButtonEnabling];
|
||||
}
|
||||
|
||||
// TODO: We could also do this in registration view.
|
||||
- (BOOL)hasValidPhoneNumber
|
||||
{
|
||||
if (!self.callingCode) {
|
||||
return NO;
|
||||
}
|
||||
NSString *possiblePhoneNumber = [self.callingCode stringByAppendingString:_phoneNumberTextField.text.digitsOnly];
|
||||
PhoneNumber *parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:possiblePhoneNumber];
|
||||
// It'd be nice to use [PhoneNumber isValid] but it always returns false for some countries
|
||||
// (like afghanistan) and there doesn't seem to be a good way to determine beforehand
|
||||
// which countries it can validate for without forking libPhoneNumber.
|
||||
return parsedPhoneNumber && parsedPhoneNumber.toE164.length > 1;
|
||||
}
|
||||
|
||||
- (void)updateBlockButtonEnabling
|
||||
{
|
||||
BOOL isEnabled = [self hasValidPhoneNumber];
|
||||
_blockButton.enabled = isEnabled;
|
||||
[_blockButton setBackgroundColor:(isEnabled ? [UIColor ows_signalBrandBlueColor] : [UIColor lightGrayColor])];
|
||||
}
|
||||
|
||||
- (void)blockedPhoneNumbersDidChange:(id)notification
|
||||
{
|
||||
// TODO: Once we have a list of contacts, we should update it here.
|
||||
}
|
||||
|
||||
#pragma mark - CountryCodeViewControllerDelegate
|
||||
|
||||
- (void)countryCodeViewController:(CountryCodeViewController *)vc
|
||||
didSelectCountryCode:(NSString *)countryCode
|
||||
countryName:(NSString *)countryName
|
||||
callingCode:(NSString *)callingCode {
|
||||
|
||||
[self updateCountryWithName:countryName
|
||||
callingCode:callingCode
|
||||
countryCode:countryCode];
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
// TODO: This logic resides in both RegistrationViewController and here.
|
||||
// We should refactor it out into a utility function.
|
||||
- (BOOL)textField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)insertionText
|
||||
{
|
||||
[ViewControllerUtils phoneNumberTextField:textField
|
||||
shouldChangeCharactersInRange:range
|
||||
replacementString:insertionText
|
||||
countryCode:_callingCode];
|
||||
|
||||
[self updateBlockButtonEnabling];
|
||||
|
||||
return NO; // inform our caller that we took care of performing the change
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
[self tryToBlockPhoneNumber];
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
9
Signal/src/ViewControllers/BlockListViewController.h
Normal file
9
Signal/src/ViewControllers/BlockListViewController.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface BlockListViewController : UITableViewController
|
||||
|
||||
@end
|
231
Signal/src/ViewControllers/BlockListViewController.m
Normal file
231
Signal/src/ViewControllers/BlockListViewController.m
Normal file
|
@ -0,0 +1,231 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BlockListViewController.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "PhoneNumber.h"
|
||||
#import "AddToBlockListViewController.h"
|
||||
#import <SignalServiceKit/OWSBlockingManager.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// TODO: We should label phone numbers with contact names where possible.
|
||||
@interface BlockListViewController ()
|
||||
|
||||
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
|
||||
@property (nonatomic, readonly) NSArray<NSString *> *blockedPhoneNumbers;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef NS_ENUM(NSInteger, BlockListViewControllerSection) {
|
||||
BlockListViewControllerSection_Add,
|
||||
BlockListViewControllerSection_BlockList,
|
||||
BlockListViewControllerSection_Count // meta section
|
||||
};
|
||||
|
||||
@implementation BlockListViewController
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [super initWithStyle:UITableViewStyleGrouped];
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
_blockingManager = [OWSBlockingManager sharedManager];
|
||||
_blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers];
|
||||
|
||||
self.title
|
||||
= NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", @"Label for the block list section of the settings view");
|
||||
|
||||
[self addNotificationListeners];
|
||||
}
|
||||
|
||||
- (void)addNotificationListeners
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(blockedPhoneNumbersDidChange:)
|
||||
name:kNSNotificationName_BlockedPhoneNumbersDidChange
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return BlockListViewControllerSection_Count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
switch (section) {
|
||||
case BlockListViewControllerSection_Add:
|
||||
return 1;
|
||||
case BlockListViewControllerSection_BlockList:
|
||||
return (NSInteger) _blockedPhoneNumbers.count;
|
||||
default:
|
||||
OWSAssert(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch (section) {
|
||||
case BlockListViewControllerSection_Add:
|
||||
return NSLocalizedString(
|
||||
@"SETTINGS_BLOCK_LIST_HEADER_TITLE", @"A header title for the block list table.");
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
OWSAssert(cell);
|
||||
|
||||
switch (indexPath.section) {
|
||||
case BlockListViewControllerSection_Add:
|
||||
cell.textLabel.text = NSLocalizedString(
|
||||
@"SETTINGS_BLOCK_LIST_ADD_BUTTON", @"A label for the 'add phone number' button in the block list table.");
|
||||
cell.textLabel.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
break;
|
||||
case BlockListViewControllerSection_BlockList: {
|
||||
NSString *phoneNumber = _blockedPhoneNumbers[(NSUInteger) indexPath.item];
|
||||
PhoneNumber *parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumber];
|
||||
// Try to parse and present the phone number in E164.
|
||||
// It should already be in E164, so this should always work.
|
||||
// If an invalid or unparsable phone number is already in the block list,
|
||||
// present it as-is.
|
||||
cell.textLabel.text = (parsedPhoneNumber
|
||||
? parsedPhoneNumber.toE164
|
||||
: phoneNumber);
|
||||
cell.textLabel.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
OWSAssert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
switch (indexPath.section) {
|
||||
case BlockListViewControllerSection_Add:
|
||||
{
|
||||
AddToBlockListViewController *vc = [[AddToBlockListViewController alloc] init];
|
||||
NSAssert(self.navigationController != nil, @"Navigation controller must not be nil");
|
||||
NSAssert(vc != nil, @"Privacy Settings View Controller must not be nil");
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
break;
|
||||
}
|
||||
case BlockListViewControllerSection_BlockList: {
|
||||
NSString *phoneNumber = _blockedPhoneNumbers[(NSUInteger)indexPath.item];
|
||||
[self showUnblockActionSheet:phoneNumber];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
OWSAssert(0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showUnblockActionSheet:(NSString *)phoneNumber
|
||||
{
|
||||
OWSAssert(phoneNumber.length > 0);
|
||||
|
||||
PhoneNumber *parsedPhoneNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumber];
|
||||
NSString *displayPhoneNumber = (parsedPhoneNumber ? parsedPhoneNumber.toE164 : phoneNumber);
|
||||
|
||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_TITLE_FORMAT",
|
||||
@"A format for the 'unblock phone number' action sheet title."),
|
||||
displayPhoneNumber];
|
||||
|
||||
UIAlertController *actionSheetController =
|
||||
[UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
__weak BlockListViewController *weakSelf = self;
|
||||
UIAlertAction *unblockAction = [UIAlertAction
|
||||
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON", @"Button label for the 'unblock' button")
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[weakSelf unblockPhoneNumber:phoneNumber displayPhoneNumber:displayPhoneNumber];
|
||||
}];
|
||||
[actionSheetController addAction:unblockAction];
|
||||
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil];
|
||||
[actionSheetController addAction:dismissAction];
|
||||
|
||||
[self presentViewController:actionSheetController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)unblockPhoneNumber:(NSString *)phoneNumber displayPhoneNumber:(NSString *)displayPhoneNumber
|
||||
{
|
||||
[_blockingManager removeBlockedPhoneNumber:phoneNumber];
|
||||
|
||||
UIAlertController *controller = [UIAlertController
|
||||
alertControllerWithTitle:NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE",
|
||||
@"The title of the 'phone number unblocked' alert in the block view.")
|
||||
message:[NSString stringWithFormat:NSLocalizedString(
|
||||
@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_MESSAGE_FORMAT",
|
||||
@"The message format of the 'phone number unblocked' "
|
||||
@"alert in the block view. It is populated with the "
|
||||
@"blocked phone number."),
|
||||
displayPhoneNumber]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - Actions
|
||||
|
||||
- (void)blockedPhoneNumbersDidChange:(id)notification
|
||||
{
|
||||
_blockedPhoneNumbers = [_blockingManager blockedPhoneNumbers];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -9,21 +9,21 @@
|
|||
@protocol CountryCodeViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)countryCodeViewController:(CountryCodeViewController *)vc
|
||||
didSelectCountryCode:(NSString *)code
|
||||
forCountry:(NSString *)country;
|
||||
|
||||
- (void)countryCodeViewControllerDidCancel:(CountryCodeViewController *)vc;
|
||||
didSelectCountryCode:(NSString *)countryCode
|
||||
countryName:(NSString *)countryName
|
||||
callingCode:(NSString *)callingCode;
|
||||
|
||||
@end
|
||||
|
||||
@interface CountryCodeViewController
|
||||
: UIViewController <UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, UISearchDisplayDelegate>
|
||||
|
||||
@property (nonatomic, strong) IBOutlet UITableView *countryCodeTableView;
|
||||
@property (nonatomic, strong) IBOutlet UISearchBar *searchBar;
|
||||
@property (nonatomic, assign) id<CountryCodeViewControllerDelegate> delegate;
|
||||
@property (nonatomic, strong) NSString *countryCodeSelected;
|
||||
@property (nonatomic, strong) NSString *callingCodeSelected;
|
||||
@property (nonatomic, strong) NSString *countryNameSelected;
|
||||
@property (nonatomic) IBOutlet UITableView *countryCodeTableView;
|
||||
@property (nonatomic) IBOutlet UISearchBar *searchBar;
|
||||
@property (nonatomic, weak) id<CountryCodeViewControllerDelegate> delegate;
|
||||
@property (nonatomic) NSString *countryCodeSelected;
|
||||
@property (nonatomic) NSString *callingCodeSelected;
|
||||
@property (nonatomic) NSString *countryNameSelected;
|
||||
@property (nonatomic) BOOL shouldDismissWithoutSegue;
|
||||
|
||||
@end
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
static NSString *const CONTRY_CODE_TABLE_CELL_IDENTIFIER = @"CountryCodeTableViewCell";
|
||||
static NSString *const kUnwindToCountryCodeWasSelectedSegue = @"UnwindToCountryCodeWasSelectedSegue";
|
||||
|
||||
|
||||
@interface CountryCodeViewController () {
|
||||
NSArray *_countryCodes;
|
||||
}
|
||||
|
@ -25,6 +24,11 @@ static NSString *const kUnwindToCountryCodeWasSelectedSegue = @"UnwindToCountryC
|
|||
_countryCodes = [PhoneNumberUtil countryCodesForSearchTerm:nil];
|
||||
self.title = NSLocalizedString(@"COUNTRYCODE_SELECT_TITLE", @"");
|
||||
self.searchBar.delegate = self;
|
||||
if (self.shouldDismissWithoutSegue) {
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
|
||||
target:self
|
||||
action:@selector(dismissWasPressed:)];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITableViewDelegate
|
||||
|
@ -57,8 +61,20 @@ static NSString *const kUnwindToCountryCodeWasSelectedSegue = @"UnwindToCountryC
|
|||
_callingCodeSelected = [PhoneNumberUtil callingCodeFromCountryCode:countryCode];
|
||||
_countryNameSelected = [PhoneNumberUtil countryNameFromCountryCode:countryCode];
|
||||
_countryCodeSelected = countryCode;
|
||||
[self.delegate countryCodeViewController:self
|
||||
didSelectCountryCode:_countryCodeSelected
|
||||
countryName:_countryNameSelected
|
||||
callingCode:_callingCodeSelected];
|
||||
[self.searchBar resignFirstResponder];
|
||||
[self performSegueWithIdentifier:kUnwindToCountryCodeWasSelectedSegue sender:self];
|
||||
if (self.shouldDismissWithoutSegue) {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
} else {
|
||||
[self performSegueWithIdentifier:kUnwindToCountryCodeWasSelectedSegue sender:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissWasPressed:(id)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
|
|
@ -2,13 +2,17 @@
|
|||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "OWSTableViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSThread;
|
||||
|
||||
@interface DebugUITableViewController : UITableViewController
|
||||
@interface DebugUITableViewController : OWSTableViewController
|
||||
|
||||
+ (void)presentDebugUIForThread:(TSThread *)thread
|
||||
fromViewController:(UIViewController *)fromViewController;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -11,205 +11,8 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSTableItem;
|
||||
@class OWSTableSection;
|
||||
|
||||
@interface OWSTableContents : NSObject
|
||||
|
||||
@property (nonatomic) NSString *title;
|
||||
@property (nonatomic) NSMutableArray<OWSTableSection *> *sections;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableContents
|
||||
|
||||
-(instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_sections = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addSection:(OWSTableSection *)section {
|
||||
OWSAssert(section);
|
||||
|
||||
[_sections addObject:section];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableSection : NSObject
|
||||
|
||||
@property (nonatomic) NSString *title;
|
||||
@property (nonatomic) NSMutableArray<OWSTableItem *> *items;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableSection
|
||||
|
||||
+ (OWSTableSection *)sectionWithTitle:(NSString *)title
|
||||
items:(NSArray *)items {
|
||||
OWSTableSection *section = [OWSTableSection new];
|
||||
section.title = title;
|
||||
section.items = [items mutableCopy];
|
||||
return section;
|
||||
}
|
||||
|
||||
-(instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_items = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addItem:(OWSTableItem *)item {
|
||||
OWSAssert(item);
|
||||
|
||||
if (!_items) {
|
||||
_items = [NSMutableArray new];
|
||||
}
|
||||
|
||||
[_items addObject:item];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef NS_ENUM(NSInteger, OWSTableItemType) {
|
||||
OWSTableItemTypeAction,
|
||||
};
|
||||
|
||||
typedef void (^OWSTableActionBlock)();
|
||||
|
||||
@interface OWSTableItem : NSObject
|
||||
|
||||
@property (nonatomic) OWSTableItemType itemType;
|
||||
@property (nonatomic) NSString *title;
|
||||
@property (nonatomic) OWSTableActionBlock actionBlock;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableItem
|
||||
|
||||
+ (OWSTableItem *)actionWithTitle:(NSString *)title
|
||||
actionBlock:(OWSTableActionBlock)actionBlock {
|
||||
OWSAssert(title.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.itemType = OWSTableItemTypeAction;
|
||||
item.actionBlock = actionBlock;
|
||||
item.title = title;
|
||||
return item;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
NSString * const kDebugUITableCellIdentifier = @"kDebugUITableCellIdentifier";
|
||||
|
||||
@interface DebugUITableViewController ()
|
||||
|
||||
@property (nonatomic) OWSTableContents *contents;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DebugUITableViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [super initWithStyle:UITableViewStyleGrouped];
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
OWSAssert(self.contents);
|
||||
|
||||
self.title = self.contents.title;
|
||||
|
||||
OWSAssert(self.tableView);
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kDebugUITableCellIdentifier];
|
||||
}
|
||||
|
||||
- (OWSTableSection *)sectionForIndex:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSAssert(self.contents);
|
||||
OWSAssert(sectionIndex >= 0 && sectionIndex < (NSInteger) self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger) sectionIndex];
|
||||
return section;
|
||||
}
|
||||
|
||||
- (OWSTableItem *)itemForIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSAssert(self.contents);
|
||||
OWSAssert(indexPath.section >= 0 && indexPath.section < (NSInteger) self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger) indexPath.section];
|
||||
OWSAssert(indexPath.item >= 0 && indexPath.item < (NSInteger) section.items.count);
|
||||
OWSTableItem *item = section.items[(NSUInteger) indexPath.item];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
OWSAssert(self.contents);
|
||||
|
||||
OWSAssert(self.contents.sections.count > 0);
|
||||
return (NSInteger) self.contents.sections.count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex {
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
OWSAssert(section.items.count > 0);
|
||||
return (NSInteger) section.items.count;
|
||||
}
|
||||
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.title;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kDebugUITableCellIdentifier];
|
||||
OWSAssert(cell);
|
||||
|
||||
cell.textLabel.text = item.title;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
if (item.itemType == OWSTableItemTypeAction) {
|
||||
OWSAssert(item.actionBlock);
|
||||
item.actionBlock();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
|
@ -323,25 +126,6 @@ NSString * const kDebugUITableCellIdentifier = @"kDebugUITableCellIdentifier";
|
|||
messageSender:messageSender];
|
||||
}
|
||||
|
||||
#pragma mark - Presentation
|
||||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController {
|
||||
OWSAssert(fromViewController);
|
||||
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self];
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
|
||||
target:self
|
||||
action:@selector(donePressed:)];
|
||||
|
||||
[fromViewController presentViewController:navigationController
|
||||
animated:YES
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
- (void)donePressed:(id)sender {
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
59
Signal/src/ViewControllers/OWSTableViewController.h
Normal file
59
Signal/src/ViewControllers/OWSTableViewController.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSTableItem;
|
||||
@class OWSTableSection;
|
||||
|
||||
@interface OWSTableContents : NSObject
|
||||
|
||||
@property (nonatomic) NSString *title;
|
||||
|
||||
- (void)addSection:(OWSTableSection *)section;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableSection : NSObject
|
||||
|
||||
@property (nonatomic, nullable) NSString *title;
|
||||
|
||||
+ (OWSTableSection *)sectionWithTitle:(NSString *)title items:(NSArray<OWSTableItem *> *)items;
|
||||
|
||||
- (void)addItem:(OWSTableItem *)item;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef NS_ENUM(NSInteger, OWSTableItemType) {
|
||||
OWSTableItemTypeAction,
|
||||
};
|
||||
|
||||
typedef void (^OWSTableActionBlock)();
|
||||
|
||||
@interface OWSTableItem : NSObject
|
||||
|
||||
+ (OWSTableItem *)actionWithTitle:(NSString *)title
|
||||
actionBlock:(OWSTableActionBlock)actionBlock;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableViewController : UITableViewController
|
||||
|
||||
@property (nonatomic) OWSTableContents *contents;
|
||||
|
||||
#pragma mark - Presentation
|
||||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
230
Signal/src/ViewControllers/OWSTableViewController.m
Normal file
230
Signal/src/ViewControllers/OWSTableViewController.m
Normal file
|
@ -0,0 +1,230 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSTableViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface OWSTableContents ()
|
||||
|
||||
@property (nonatomic) NSMutableArray<OWSTableSection *> *sections;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableContents
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_sections = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addSection:(OWSTableSection *)section
|
||||
{
|
||||
OWSAssert(section);
|
||||
|
||||
[_sections addObject:section];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableSection ()
|
||||
|
||||
@property (nonatomic) NSMutableArray<OWSTableItem *> *items;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableSection
|
||||
|
||||
+ (OWSTableSection *)sectionWithTitle:(NSString *)title items:(NSArray<OWSTableItem *> *)items
|
||||
{
|
||||
OWSTableSection *section = [OWSTableSection new];
|
||||
section.title = title;
|
||||
section.items = [items mutableCopy];
|
||||
return section;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
if (self = [super init]) {
|
||||
_items = [NSMutableArray new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addItem:(OWSTableItem *)item
|
||||
{
|
||||
OWSAssert(item);
|
||||
|
||||
[_items addObject:item];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface OWSTableItem ()
|
||||
|
||||
@property (nonatomic) OWSTableItemType itemType;
|
||||
@property (nonatomic, nullable) NSString *title;
|
||||
@property (nonatomic, nullable) OWSTableActionBlock actionBlock;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSTableItem
|
||||
|
||||
+ (OWSTableItem *)actionWithTitle:(NSString *)title actionBlock:(OWSTableActionBlock)actionBlock
|
||||
{
|
||||
OWSAssert(title.length > 0);
|
||||
|
||||
OWSTableItem *item = [OWSTableItem new];
|
||||
item.itemType = OWSTableItemTypeAction;
|
||||
item.actionBlock = actionBlock;
|
||||
item.title = title;
|
||||
return item;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
NSString * const kOWSTableCellIdentifier = @"kOWSTableCellIdentifier";
|
||||
|
||||
@implementation OWSTableViewController
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [super initWithStyle:UITableViewStyleGrouped];
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
OWSAssert(self.contents);
|
||||
|
||||
self.title = self.contents.title;
|
||||
|
||||
OWSAssert(self.tableView);
|
||||
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kOWSTableCellIdentifier];
|
||||
}
|
||||
|
||||
- (OWSTableSection *)sectionForIndex:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSAssert(self.contents);
|
||||
OWSAssert(sectionIndex >= 0 && sectionIndex < (NSInteger) self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger) sectionIndex];
|
||||
return section;
|
||||
}
|
||||
|
||||
- (OWSTableItem *)itemForIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSAssert(self.contents);
|
||||
OWSAssert(indexPath.section >= 0 && indexPath.section < (NSInteger) self.contents.sections.count);
|
||||
|
||||
OWSTableSection *section = self.contents.sections[(NSUInteger) indexPath.section];
|
||||
OWSAssert(indexPath.item >= 0 && indexPath.item < (NSInteger) section.items.count);
|
||||
OWSTableItem *item = section.items[(NSUInteger) indexPath.item];
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
OWSAssert(self.contents);
|
||||
|
||||
OWSAssert(self.contents.sections.count > 0);
|
||||
return (NSInteger) self.contents.sections.count;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
OWSAssert(section.items.count > 0);
|
||||
return (NSInteger) section.items.count;
|
||||
}
|
||||
|
||||
- (nullable NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)sectionIndex
|
||||
{
|
||||
OWSTableSection *section = [self sectionForIndex:sectionIndex];
|
||||
return section.title;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kOWSTableCellIdentifier];
|
||||
OWSAssert(cell);
|
||||
|
||||
cell.textLabel.text = item.title;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
OWSTableItem *item = [self itemForIndexPath:indexPath];
|
||||
if (item.itemType == OWSTableItemTypeAction) {
|
||||
OWSAssert(item.actionBlock);
|
||||
item.actionBlock();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
#pragma mark - Presentation
|
||||
|
||||
- (void)presentFromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssert(fromViewController);
|
||||
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self];
|
||||
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemStop
|
||||
target:self
|
||||
action:@selector(donePressed:)];
|
||||
|
||||
[fromViewController presentViewController:navigationController
|
||||
animated:YES
|
||||
completion:nil];
|
||||
}
|
||||
|
||||
- (void)donePressed:(id)sender
|
||||
{
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -3,16 +3,17 @@
|
|||
//
|
||||
|
||||
#import "PrivacySettingsTableViewController.h"
|
||||
|
||||
#import "BlockListViewController.h"
|
||||
#import "Environment.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "UIUtil.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import "UIUtil.h"
|
||||
#import <25519/Curve25519.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
||||
PrivacySettingsTableViewControllerSectionIndexBlockList,
|
||||
PrivacySettingsTableViewControllerSectionIndexScreenSecurity,
|
||||
PrivacySettingsTableViewControllerSectionIndexCalling,
|
||||
PrivacySettingsTableViewControllerSectionIndexCallKit,
|
||||
|
@ -23,6 +24,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
|||
|
||||
@interface PrivacySettingsTableViewController ()
|
||||
|
||||
@property (nonatomic) UITableViewCell *blocklistCell;
|
||||
|
||||
@property (nonatomic) UITableViewCell *enableCallKitCell;
|
||||
@property (nonatomic) UISwitch *enableCallKitSwitch;
|
||||
|
||||
|
@ -60,6 +63,12 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
|||
|
||||
self.title = NSLocalizedString(@"SETTINGS_PRIVACY_TITLE", @"");
|
||||
|
||||
// Block List
|
||||
self.blocklistCell = [UITableViewCell new];
|
||||
self.blocklistCell.textLabel.text
|
||||
= NSLocalizedString(@"SETTINGS_BLOCK_LIST_TITLE", @"Label for the block list section of the settings view");
|
||||
self.blocklistCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
|
||||
|
||||
// CallKit opt-out
|
||||
self.enableCallKitCell = [UITableViewCell new];
|
||||
self.enableCallKitCell.textLabel.text = NSLocalizedString(@"SETTINGS_PRIVACY_CALLKIT_TITLE", @"Short table cell label");
|
||||
|
@ -127,6 +136,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
|||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
switch (section) {
|
||||
case PrivacySettingsTableViewControllerSectionIndexBlockList:
|
||||
return 1;
|
||||
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
|
||||
return 1;
|
||||
case PrivacySettingsTableViewControllerSectionIndexCalling:
|
||||
|
@ -167,6 +178,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
|||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
switch (indexPath.section) {
|
||||
case PrivacySettingsTableViewControllerSectionIndexBlockList:
|
||||
return self.blocklistCell;
|
||||
case PrivacySettingsTableViewControllerSectionIndexScreenSecurity:
|
||||
return self.enableScreenSecurityCell;
|
||||
case PrivacySettingsTableViewControllerSectionIndexCalling:
|
||||
|
@ -209,6 +222,13 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) {
|
|||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
switch (indexPath.section) {
|
||||
case PrivacySettingsTableViewControllerSectionIndexBlockList: {
|
||||
BlockListViewController *vc = [[BlockListViewController alloc] init];
|
||||
NSAssert(self.navigationController != nil, @"Navigation controller must not be nil");
|
||||
NSAssert(vc != nil, @"About View Controller must not be nil");
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
break;
|
||||
}
|
||||
case PrivacySettingsTableViewControllerSectionIndexHistoryLog: {
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:nil
|
||||
message:NSLocalizedString(@"SETTINGS_DELETE_HISTORYLOG_CONFIRMATION", @"Alert message before user confirms clearing history")
|
||||
|
|
|
@ -9,17 +9,20 @@
|
|||
#import "PhoneNumberUtil.h"
|
||||
#import "SignalKeyingStorage.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import "Util.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import "Util.h"
|
||||
#import "ViewControllerUtils.h"
|
||||
|
||||
static NSString *const kCodeSentSegue = @"codeSent";
|
||||
|
||||
@interface RegistrationViewController ()
|
||||
|
||||
@property (nonatomic) NSString *lastCallingCode;
|
||||
@property (nonatomic) NSString *callingCode;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation RegistrationViewController
|
||||
|
||||
- (void)viewDidLoad {
|
||||
|
@ -32,11 +35,14 @@ static NSString *const kCodeSentSegue = @"codeSent";
|
|||
[[Environment getCurrent] setSignUpFlowNavigationController:self.navigationController];
|
||||
|
||||
_titleLabel.text = NSLocalizedString(@"REGISTRATION_TITLE_LABEL", @"");
|
||||
[_countryNameButton setTitle:NSLocalizedString(@"REGISTRATION_DEFAULT_COUNTRY_NAME", @"")
|
||||
forState:UIControlStateNormal];
|
||||
_phoneNumberTextField.placeholder = NSLocalizedString(@"REGISTRATION_ENTERNUMBER_DEFAULT_TEXT", @"");
|
||||
[_phoneNumberButton setTitle:NSLocalizedString(@"REGISTRATION_PHONENUMBER_BUTTON", @"")
|
||||
forState:UIControlStateNormal];
|
||||
[_countryNameButton
|
||||
setTitle:NSLocalizedString(@"REGISTRATION_DEFAULT_COUNTRY_NAME", @"Label for the country code field")
|
||||
forState:UIControlStateNormal];
|
||||
_phoneNumberTextField.placeholder = NSLocalizedString(
|
||||
@"REGISTRATION_ENTERNUMBER_DEFAULT_TEXT", @"Placeholder text for the phone number textfield");
|
||||
[_phoneNumberButton
|
||||
setTitle:NSLocalizedString(@"REGISTRATION_PHONENUMBER_BUTTON", @"Label for the phone number textfield")
|
||||
forState:UIControlStateNormal];
|
||||
[_phoneNumberButton.titleLabel setAdjustsFontSizeToFitWidth:YES];
|
||||
[_sendCodeButton setTitle:NSLocalizedString(@"REGISTRATION_VERIFY_DEVICE", @"") forState:UIControlStateNormal];
|
||||
[_existingUserButton setTitle:NSLocalizedString(@"ALREADY_HAVE_ACCOUNT_BUTTON", @"registration button text")
|
||||
|
@ -73,7 +79,7 @@ static NSString *const kCodeSentSegue = @"codeSent";
|
|||
callingCode:(NSString *)callingCode
|
||||
countryCode:(NSString *)countryCode {
|
||||
|
||||
_lastCallingCode = callingCode;
|
||||
_callingCode = callingCode;
|
||||
|
||||
NSString *title = [NSString stringWithFormat:@"%@ (%@)",
|
||||
callingCode,
|
||||
|
@ -128,7 +134,7 @@ static NSString *const kCodeSentSegue = @"codeSent";
|
|||
}
|
||||
|
||||
- (IBAction)sendCodeAction:(id)sender {
|
||||
NSString *phoneNumber = [NSString stringWithFormat:@"%@%@", _lastCallingCode, _phoneNumberTextField.text];
|
||||
NSString *phoneNumber = [NSString stringWithFormat:@"%@%@", _callingCode, _phoneNumberTextField.text];
|
||||
PhoneNumber *localNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumber];
|
||||
|
||||
[_sendCodeButton setEnabled:NO];
|
||||
|
@ -187,50 +193,12 @@ static NSString *const kCodeSentSegue = @"codeSent";
|
|||
- (BOOL)textField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)insertionText {
|
||||
|
||||
// Phone numbers takes many forms.
|
||||
//
|
||||
// * We only want to let the user enter decimal digits.
|
||||
// * The user shouldn't have to enter hyphen, parentheses or whitespace;
|
||||
// the phone number should be formatted automatically.
|
||||
// * The user should be able to copy and paste freely.
|
||||
// * Invalid input should be simply ignored.
|
||||
//
|
||||
// We accomplish this by being permissive and trying to "take as much of the user
|
||||
// input as possible".
|
||||
//
|
||||
// * Always accept deletes.
|
||||
// * Ignore invalid input.
|
||||
// * Take partial input if possible.
|
||||
|
||||
NSString *oldText = textField.text;
|
||||
// Construct the new contents of the text field by:
|
||||
// 1. Determining the "left" substring: the contents of the old text _before_ the deletion range.
|
||||
// Filtering will remove non-decimal digit characters like hyphen "-".
|
||||
NSString *left = [oldText substringToIndex:range.location].digitsOnly;
|
||||
// 2. Determining the "right" substring: the contents of the old text _after_ the deletion range.
|
||||
NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly;
|
||||
// 3. Determining the "center" substring: the contents of the new insertion text.
|
||||
NSString *center = insertionText.digitsOnly;
|
||||
// 4. Construct the "raw" new text by concatenating left, center and right.
|
||||
NSString *textAfterChange = [[left stringByAppendingString:center]
|
||||
stringByAppendingString:right];
|
||||
// 5. Construct the "formatted" new text by inserting a hyphen if necessary.
|
||||
// reformat the phone number, trying to keep the cursor beside the inserted or deleted digit
|
||||
bool isJustDeletion = insertionText.length == 0;
|
||||
NSUInteger cursorPositionAfterChange = left.length + center.length;
|
||||
NSString *textAfterReformat =
|
||||
[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:textAfterChange
|
||||
withSpecifiedCountryCodeString:_countryCodeButton.titleLabel.text];
|
||||
NSUInteger cursorPositionAfterReformat = [PhoneNumberUtil translateCursorPosition:cursorPositionAfterChange
|
||||
from:textAfterChange
|
||||
to:textAfterReformat
|
||||
stickingRightward:isJustDeletion];
|
||||
textField.text = textAfterReformat;
|
||||
UITextPosition *pos =
|
||||
[textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterReformat];
|
||||
[textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]];
|
||||
|
||||
|
||||
[ViewControllerUtils phoneNumberTextField:textField
|
||||
shouldChangeCharactersInRange:range
|
||||
replacementString:insertionText
|
||||
countryCode:_callingCode];
|
||||
|
||||
return NO; // inform our caller that we took care of performing the change
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
//
|
||||
// SettingsTableViewController.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Dylan Bourgeois on 03/11/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
|
19
Signal/src/ViewControllers/ViewControllerUtils.h
Normal file
19
Signal/src/ViewControllers/ViewControllerUtils.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface ViewControllerUtils : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
// This convenience function can be used to reformat the contents of
|
||||
// a phone number text field as the user modifies its text by typing,
|
||||
// pasting, etc.
|
||||
+ (void)phoneNumberTextField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)insertionText
|
||||
countryCode:(NSString *)countryCode;
|
||||
|
||||
@end
|
73
Signal/src/ViewControllers/ViewControllerUtils.m
Normal file
73
Signal/src/ViewControllers/ViewControllerUtils.m
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ViewControllerUtils.h"
|
||||
#import "PhoneNumber.h"
|
||||
#import "StringUtil.h"
|
||||
#import <SignalServiceKit/PhoneNumberUtil.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ViewControllerUtils
|
||||
|
||||
+ (void)phoneNumberTextField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)insertionText
|
||||
countryCode:(NSString *)countryCode
|
||||
{
|
||||
|
||||
// Phone numbers takes many forms.
|
||||
//
|
||||
// * We only want to let the user enter decimal digits.
|
||||
// * The user shouldn't have to enter hyphen, parentheses or whitespace;
|
||||
// the phone number should be formatted automatically.
|
||||
// * The user should be able to copy and paste freely.
|
||||
// * Invalid input should be simply ignored.
|
||||
//
|
||||
// We accomplish this by being permissive and trying to "take as much of the user
|
||||
// input as possible".
|
||||
//
|
||||
// * Always accept deletes.
|
||||
// * Ignore invalid input.
|
||||
// * Take partial input if possible.
|
||||
|
||||
NSString *oldText = textField.text;
|
||||
// Construct the new contents of the text field by:
|
||||
// 1. Determining the "left" substring: the contents of the old text _before_ the deletion range.
|
||||
// Filtering will remove non-decimal digit characters like hyphen "-".
|
||||
NSString *left = [oldText substringToIndex:range.location].digitsOnly;
|
||||
// 2. Determining the "right" substring: the contents of the old text _after_ the deletion range.
|
||||
NSString *right = [oldText substringFromIndex:range.location + range.length].digitsOnly;
|
||||
// 3. Determining the "center" substring: the contents of the new insertion text.
|
||||
NSString *center = insertionText.digitsOnly;
|
||||
// 4. Construct the "raw" new text by concatenating left, center and right.
|
||||
NSString *textAfterChange = [[left stringByAppendingString:center] stringByAppendingString:right];
|
||||
// 4a. Ensure we don't exceed the maximum length for a e164 phone number,
|
||||
// 15 digits, per: https://en.wikipedia.org/wiki/E.164
|
||||
const int kMaxPhoneNumberLength = 15;
|
||||
if (textAfterChange.length > kMaxPhoneNumberLength) {
|
||||
textAfterChange = [textAfterChange substringToIndex:kMaxPhoneNumberLength];
|
||||
}
|
||||
// 5. Construct the "formatted" new text by inserting a hyphen if necessary.
|
||||
// reformat the phone number, trying to keep the cursor beside the inserted or deleted digit
|
||||
bool isJustDeletion = insertionText.length == 0;
|
||||
NSUInteger cursorPositionAfterChange = MIN(left.length + center.length, textAfterChange.length);
|
||||
NSString *textAfterReformat =
|
||||
[PhoneNumber bestEffortFormatPartialUserSpecifiedTextToLookLikeAPhoneNumber:textAfterChange
|
||||
withSpecifiedCountryCodeString:countryCode];
|
||||
NSUInteger cursorPositionAfterReformat = [PhoneNumberUtil translateCursorPosition:cursorPositionAfterChange
|
||||
from:textAfterChange
|
||||
to:textAfterReformat
|
||||
stickingRightward:isJustDeletion];
|
||||
textField.text = textAfterReformat;
|
||||
UITextPosition *pos =
|
||||
[textField positionFromPosition:textField.beginningOfDocument offset:(NSInteger)cursorPositionAfterReformat];
|
||||
[textField setSelectedTextRange:[textField textRangeFromPosition:pos toPosition:pos]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -97,11 +97,26 @@
|
|||
/* No comment provided by engineer. */
|
||||
"ATTACHMENT_QUEUED" = "New attachment queued for retrieval.";
|
||||
|
||||
/* A message indicating that an attachment of unknown type was received. */
|
||||
"ATTACHMENT_UNKNOWN_TYPE" = "Unknown attachment received";
|
||||
/* Button label for the 'unblock' button */
|
||||
"BLOCK_LIST_UNBLOCK_BUTTON" = "Unblock";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"AUDIO_PERMISSION_MESSAGE" = "Signal requires access to your microphone to work properly. You can grant this permission in the Settings app >> Privacy >> Microphone >> Signal";
|
||||
/* A format for the 'unblock phone number' action sheet title. */
|
||||
"BLOCK_LIST_UNBLOCK_TITLE_FORMAT" = "Unblock %@?";
|
||||
|
||||
/* A label for the block button in the block list view */
|
||||
"BLOCK_LIST_VIEW_BLOCK_BUTTON" = "Block";
|
||||
|
||||
/* The message format of the 'phone number blocked' alert in the block view. It is populated with the blocked phone number. */
|
||||
"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT" = "%@ has been blocked.";
|
||||
|
||||
/* The title of the 'phone number blocked' alert in the block view. */
|
||||
"BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE" = "Phone Number Blocked";
|
||||
|
||||
/* The message format of the 'phone number unblocked' alert in the block view. It is populated with the blocked phone number. */
|
||||
"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_MESSAGE_FORMAT" = "%@ has been unblocked.";
|
||||
|
||||
/* The title of the 'phone number unblocked' alert in the block view. */
|
||||
"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE" = "Phone Number Unblocked";
|
||||
|
||||
/* Accessibilty label for placing call button */
|
||||
"CALL_LABEL" = "Call";
|
||||
|
@ -790,6 +805,9 @@
|
|||
/* Navbar title */
|
||||
"SETTINGS_ABOUT" = "About";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SETTINGS_ADD_TO_BLOCK_LIST_TITLE" = "Add to Block List";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"SETTINGS_ADVANCED_DEBUGLOG" = "Enable Debug Log";
|
||||
|
||||
|
@ -799,6 +817,15 @@
|
|||
/* No comment provided by engineer. */
|
||||
"SETTINGS_ADVANCED_TITLE" = "Advanced";
|
||||
|
||||
/* A label for the 'add phone number' button in the block list table. */
|
||||
"SETTINGS_BLOCK_LIST_ADD_BUTTON" = "Add Phone Number";
|
||||
|
||||
/* A header title for the block list table. */
|
||||
"SETTINGS_BLOCK_LIST_HEADER_TITLE" = "Blocked Phone Numbers";
|
||||
|
||||
/* Label for the block list row of the settings view */
|
||||
"SETTINGS_BLOCK_LIST_TITLE" = "Blocked";
|
||||
|
||||
/* User settings section footer, a detailed explanation */
|
||||
"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL" = "Requires your approval before communicating with someone who has a new safety number, commonly from a reinstall of Signal.";
|
||||
|
||||
|
|
Loading…
Reference in a new issue