mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
29d08545e2
- [ ] document picker - [ ] camera picker - [ ] image picker - [ ] restore "confirm to go back" behavior (interactive pop gesture?) // FREEBIE
617 lines
23 KiB
Objective-C
617 lines
23 KiB
Objective-C
//
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
#import "ProfileViewController.h"
|
|
#import "AppDelegate.h"
|
|
#import "AvatarViewHelper.h"
|
|
#import "HomeViewController.h"
|
|
#import "OWSNavigationController.h"
|
|
#import "Signal-Swift.h"
|
|
#import "SignalsNavigationController.h"
|
|
#import "UIColor+OWS.h"
|
|
#import "UIFont+OWS.h"
|
|
#import "UIView+OWS.h"
|
|
#import <SignalMessaging/NSString+OWS.h>
|
|
#import <SignalMessaging/OWSNavigationController.h>
|
|
#import <SignalMessaging/OWSProfileManager.h>
|
|
#import <SignalMessaging/UIViewController+OWS.h>
|
|
#import <SignalServiceKit/NSDate+OWS.h>
|
|
#import <SignalServiceKit/OWSPrimaryStorage.h>
|
|
|
|
NS_ASSUME_NONNULL_BEGIN
|
|
|
|
typedef NS_ENUM(NSInteger, ProfileViewMode) {
|
|
ProfileViewMode_AppSettings = 0,
|
|
ProfileViewMode_Registration,
|
|
ProfileViewMode_UpgradeOrNag,
|
|
};
|
|
|
|
NSString *const kProfileView_Collection = @"kProfileView_Collection";
|
|
NSString *const kProfileView_LastPresentedDate = @"kProfileView_LastPresentedDate";
|
|
|
|
@interface ProfileViewController () <UITextFieldDelegate, AvatarViewHelperDelegate, OWSNavigationView>
|
|
|
|
@property (nonatomic, readonly) AvatarViewHelper *avatarViewHelper;
|
|
|
|
@property (nonatomic) UITextField *nameTextField;
|
|
|
|
@property (nonatomic) AvatarImageView *avatarView;
|
|
|
|
@property (nonatomic) UIImageView *cameraImageView;
|
|
|
|
@property (nonatomic) OWSFlatButton *saveButton;
|
|
|
|
@property (nonatomic, nullable) UIImage *avatar;
|
|
|
|
@property (nonatomic) BOOL hasUnsavedChanges;
|
|
|
|
@property (nonatomic) ProfileViewMode profileViewMode;
|
|
|
|
@end
|
|
|
|
#pragma mark -
|
|
|
|
@implementation ProfileViewController
|
|
|
|
- (instancetype)initWithMode:(ProfileViewMode)profileViewMode
|
|
{
|
|
self = [super init];
|
|
|
|
if (!self) {
|
|
return self;
|
|
}
|
|
|
|
self.profileViewMode = profileViewMode;
|
|
|
|
// Use the OWSPrimaryStorage.dbReadWriteConnection for consistency with the reads below.
|
|
[[[OWSPrimaryStorage sharedManager] dbReadWriteConnection] setDate:[NSDate new]
|
|
forKey:kProfileView_LastPresentedDate
|
|
inCollection:kProfileView_Collection];
|
|
|
|
return self;
|
|
}
|
|
|
|
- (void)loadView
|
|
{
|
|
[super loadView];
|
|
|
|
self.title = NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view.");
|
|
|
|
_avatarViewHelper = [AvatarViewHelper new];
|
|
_avatarViewHelper.delegate = self;
|
|
|
|
_avatar = [OWSProfileManager.sharedManager localProfileAvatarImage];
|
|
|
|
[self createViews];
|
|
[self updateNavigationItem];
|
|
}
|
|
|
|
- (void)createViews
|
|
{
|
|
self.view.backgroundColor = [UIColor colorWithRGBHex:0xefeff4];
|
|
|
|
UIView *contentView = [UIView containerView];
|
|
contentView.backgroundColor = [UIColor whiteColor];
|
|
[self.view addSubview:contentView];
|
|
[contentView autoPinToTopLayoutGuideOfViewController:self withInset:0];
|
|
[contentView autoPinWidthToSuperview];
|
|
|
|
const CGFloat fontSizePoints = ScaleFromIPhone5To7Plus(16.f, 20.f);
|
|
NSMutableArray<UIView *> *rows = [NSMutableArray new];
|
|
|
|
// Name
|
|
|
|
UIView *nameRow = [UIView containerView];
|
|
nameRow.userInteractionEnabled = YES;
|
|
[nameRow
|
|
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(nameRowTapped:)]];
|
|
[rows addObject:nameRow];
|
|
|
|
UILabel *nameLabel = [UILabel new];
|
|
nameLabel.text = NSLocalizedString(
|
|
@"PROFILE_VIEW_PROFILE_NAME_FIELD", @"Label for the profile name field of the profile view.");
|
|
nameLabel.textColor = [UIColor blackColor];
|
|
nameLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
|
|
[nameRow addSubview:nameLabel];
|
|
[nameLabel autoPinLeadingToSuperviewMargin];
|
|
[nameLabel autoPinHeightToSuperviewWithMargin:5.f];
|
|
|
|
UITextField *nameTextField = [UITextField new];
|
|
_nameTextField = nameTextField;
|
|
nameTextField.font = [UIFont ows_mediumFontWithSize:18.f];
|
|
nameTextField.textColor = [UIColor ows_materialBlueColor];
|
|
nameTextField.placeholder = NSLocalizedString(
|
|
@"PROFILE_VIEW_NAME_DEFAULT_TEXT", @"Default text for the profile name field of the profile view.");
|
|
nameTextField.delegate = self;
|
|
nameTextField.text = [OWSProfileManager.sharedManager localProfileName];
|
|
nameTextField.textAlignment = NSTextAlignmentRight;
|
|
nameTextField.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
|
|
[nameTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
|
|
[nameRow addSubview:nameTextField];
|
|
[nameTextField autoPinLeadingToTrailingEdgeOfView:nameLabel offset:10.f];
|
|
[nameTextField autoPinTrailingToSuperviewMargin];
|
|
[nameTextField autoVCenterInSuperview];
|
|
|
|
// Avatar
|
|
|
|
UIView *avatarRow = [UIView containerView];
|
|
avatarRow.userInteractionEnabled = YES;
|
|
[avatarRow
|
|
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(avatarRowTapped:)]];
|
|
[rows addObject:avatarRow];
|
|
|
|
UILabel *avatarLabel = [UILabel new];
|
|
avatarLabel.text = NSLocalizedString(
|
|
@"PROFILE_VIEW_PROFILE_AVATAR_FIELD", @"Label for the profile avatar field of the profile view.");
|
|
avatarLabel.textColor = [UIColor blackColor];
|
|
avatarLabel.font = [UIFont ows_mediumFontWithSize:fontSizePoints];
|
|
[avatarRow addSubview:avatarLabel];
|
|
[avatarLabel autoPinLeadingToSuperviewMargin];
|
|
[avatarLabel autoVCenterInSuperview];
|
|
|
|
self.avatarView = [AvatarImageView new];
|
|
|
|
UIImage *cameraImage = [UIImage imageNamed:@"settings-avatar-camera"];
|
|
self.cameraImageView = [[UIImageView alloc] initWithImage:cameraImage];
|
|
|
|
[avatarRow addSubview:self.avatarView];
|
|
[avatarRow addSubview:self.cameraImageView];
|
|
[self updateAvatarView];
|
|
[self.avatarView autoPinTrailingToSuperviewMargin];
|
|
[self.avatarView autoPinLeadingToTrailingEdgeOfView:avatarLabel offset:10.f];
|
|
const CGFloat kAvatarSizePoints = 50.f;
|
|
const CGFloat kAvatarVMargin = 4.f;
|
|
[self.avatarView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kAvatarVMargin];
|
|
[self.avatarView autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kAvatarVMargin];
|
|
[self.avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSizePoints];
|
|
[self.avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSizePoints];
|
|
[self.cameraImageView autoPinTrailingToEdgeOfView:self.avatarView];
|
|
[self.cameraImageView autoPinEdge:ALEdgeBottom toEdge:ALEdgeBottom ofView:self.avatarView];
|
|
|
|
// Information
|
|
|
|
UIView *infoRow = [UIView containerView];
|
|
infoRow.userInteractionEnabled = YES;
|
|
[infoRow
|
|
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(infoRowTapped:)]];
|
|
[rows addObject:infoRow];
|
|
|
|
UILabel *infoLabel = [UILabel new];
|
|
infoLabel.textColor = [UIColor ows_darkGrayColor];
|
|
infoLabel.font = [UIFont ows_regularFontWithSize:11.f];
|
|
infoLabel.textAlignment = NSTextAlignmentCenter;
|
|
NSMutableAttributedString *text = [NSMutableAttributedString new];
|
|
[text appendAttributedString:[[NSAttributedString alloc]
|
|
initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION",
|
|
@"Description of the user profile.")
|
|
attributes:@{}]];
|
|
[text appendAttributedString:[[NSAttributedString alloc] initWithString:@" " attributes:@{}]];
|
|
[text appendAttributedString:[[NSAttributedString alloc]
|
|
initWithString:NSLocalizedString(@"PROFILE_VIEW_PROFILE_DESCRIPTION_LINK",
|
|
@"Link to more information about the user profile.")
|
|
attributes:@{
|
|
NSUnderlineStyleAttributeName :
|
|
@(NSUnderlineStyleSingle | NSUnderlinePatternSolid),
|
|
NSForegroundColorAttributeName : [UIColor ows_materialBlueColor],
|
|
}]];
|
|
infoLabel.attributedText = text;
|
|
infoLabel.numberOfLines = 0;
|
|
infoLabel.lineBreakMode = NSLineBreakByWordWrapping;
|
|
[infoRow addSubview:infoLabel];
|
|
[infoLabel autoPinLeadingToSuperviewMargin];
|
|
[infoLabel autoPinTrailingToSuperviewMargin];
|
|
[infoLabel autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:10.f];
|
|
[infoLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:10.f];
|
|
|
|
// Big Button
|
|
|
|
if (self.profileViewMode == ProfileViewMode_Registration || self.profileViewMode == ProfileViewMode_UpgradeOrNag) {
|
|
UIView *buttonRow = [UIView containerView];
|
|
[rows addObject:buttonRow];
|
|
|
|
const CGFloat kButtonHeight = 47.f;
|
|
// NOTE: We use ows_signalBrandBlueColor instead of ows_materialBlueColor
|
|
// throughout the onboarding flow to be consistent with the headers.
|
|
OWSFlatButton *saveButton =
|
|
[OWSFlatButton buttonWithTitle:NSLocalizedString(@"PROFILE_VIEW_SAVE_BUTTON",
|
|
@"Button to save the profile view in the profile view.")
|
|
font:[OWSFlatButton fontForHeight:kButtonHeight]
|
|
titleColor:[UIColor whiteColor]
|
|
backgroundColor:[UIColor ows_signalBrandBlueColor]
|
|
target:self
|
|
selector:@selector(saveButtonPressed)];
|
|
self.saveButton = saveButton;
|
|
[buttonRow addSubview:saveButton];
|
|
[saveButton autoPinLeadingAndTrailingToSuperviewMargin];
|
|
[saveButton autoPinHeightToSuperview];
|
|
[saveButton autoSetDimension:ALDimensionHeight toSize:47.f];
|
|
}
|
|
|
|
// Row Layout
|
|
|
|
UIView *_Nullable lastRow = nil;
|
|
for (UIView *row in rows) {
|
|
[contentView addSubview:row];
|
|
if (lastRow) {
|
|
[row autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastRow withOffset:5.f];
|
|
} else {
|
|
[row autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:15.f];
|
|
}
|
|
[row autoPinLeadingToSuperviewMarginWithInset:18.f];
|
|
[row autoPinTrailingToSuperviewMarginWithInset:18.f];
|
|
lastRow = row;
|
|
|
|
if (lastRow == nameRow || lastRow == avatarRow) {
|
|
UIView *separator = [UIView containerView];
|
|
separator.backgroundColor = [UIColor colorWithWhite:0.9f alpha:1.f];
|
|
[contentView addSubview:separator];
|
|
[separator autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:lastRow withOffset:5.f];
|
|
[separator autoPinLeadingToSuperviewMarginWithInset:18.f];
|
|
[separator autoPinTrailingToSuperviewMarginWithInset:18.f];
|
|
[separator autoSetDimension:ALDimensionHeight toSize:1.f];
|
|
lastRow = separator;
|
|
}
|
|
}
|
|
[lastRow autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:10.f];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
[self.nameTextField becomeFirstResponder];
|
|
}
|
|
|
|
#pragma mark - Event Handling
|
|
|
|
- (void)backOrSkipButtonPressed
|
|
{
|
|
[self leaveViewCheckingForUnsavedChanges];
|
|
}
|
|
|
|
- (void)leaveViewCheckingForUnsavedChanges
|
|
{
|
|
[self.nameTextField resignFirstResponder];
|
|
|
|
if (!self.hasUnsavedChanges) {
|
|
// If user made no changes, return to conversation settings view.
|
|
[self profileCompletedOrSkipped];
|
|
return;
|
|
}
|
|
|
|
UIAlertController *controller = [UIAlertController
|
|
alertControllerWithTitle:
|
|
NSLocalizedString(@"NEW_GROUP_VIEW_UNSAVED_CHANGES_TITLE",
|
|
@"The alert title if user tries to exit the new group view without saving changes.")
|
|
message:
|
|
NSLocalizedString(@"NEW_GROUP_VIEW_UNSAVED_CHANGES_MESSAGE",
|
|
@"The alert message if user tries to exit the new group view without saving changes.")
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
[controller
|
|
addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"ALERT_DISCARD_BUTTON",
|
|
@"The label for the 'discard' button in alerts and action sheets.")
|
|
style:UIAlertActionStyleDestructive
|
|
handler:^(UIAlertAction *action) {
|
|
[self profileCompletedOrSkipped];
|
|
}]];
|
|
[controller addAction:[OWSAlerts cancelAction]];
|
|
[self presentViewController:controller animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)avatarTapped
|
|
{
|
|
[self.avatarViewHelper showChangeAvatarUI];
|
|
}
|
|
|
|
- (void)setHasUnsavedChanges:(BOOL)hasUnsavedChanges
|
|
{
|
|
_hasUnsavedChanges = hasUnsavedChanges;
|
|
|
|
[self updateNavigationItem];
|
|
}
|
|
|
|
- (void)updateNavigationItem
|
|
{
|
|
// The navigation bar is hidden in the registration workflow.
|
|
if (self.navigationController.navigationBarHidden) {
|
|
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
|
}
|
|
|
|
// Always display a left item to leave the view without making changes.
|
|
// This might be a "back", "skip" or "cancel" button depending on the
|
|
// context.
|
|
switch (self.profileViewMode) {
|
|
case ProfileViewMode_AppSettings:
|
|
if (self.hasUnsavedChanges) {
|
|
// If we have a unsaved changes, right item should be a "save" button.
|
|
self.navigationItem.rightBarButtonItem =
|
|
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave
|
|
target:self
|
|
action:@selector(updatePressed)];
|
|
} else {
|
|
self.navigationItem.rightBarButtonItem = nil;
|
|
}
|
|
break;
|
|
case ProfileViewMode_UpgradeOrNag:
|
|
case ProfileViewMode_Registration:
|
|
self.navigationItem.hidesBackButton = YES;
|
|
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc]
|
|
initWithTitle:NSLocalizedString(@"NAVIGATION_ITEM_SKIP_BUTTON", @"A button to skip a view.")
|
|
style:UIBarButtonItemStylePlain
|
|
target:self
|
|
action:@selector(backOrSkipButtonPressed)];
|
|
break;
|
|
}
|
|
|
|
// The save button is only used in "registration" and "upgrade or nag" modes.
|
|
if (self.hasUnsavedChanges) {
|
|
self.saveButton.enabled = YES;
|
|
[self.saveButton setBackgroundColorsWithUpColor:[UIColor ows_signalBrandBlueColor]];
|
|
} else {
|
|
self.saveButton.enabled = NO;
|
|
[self.saveButton
|
|
setBackgroundColorsWithUpColor:[[UIColor ows_signalBrandBlueColor] blendWithColor:[UIColor whiteColor]
|
|
alpha:0.5f]];
|
|
}
|
|
}
|
|
|
|
- (void)updatePressed
|
|
{
|
|
[self updateProfile];
|
|
}
|
|
|
|
- (void)updateProfile
|
|
{
|
|
__weak ProfileViewController *weakSelf = self;
|
|
|
|
NSString *normalizedProfileName = [self normalizedProfileName];
|
|
if ([OWSProfileManager.sharedManager isProfileNameTooLong:normalizedProfileName]) {
|
|
[OWSAlerts
|
|
showErrorAlertWithMessage:NSLocalizedString(@"PROFILE_VIEW_ERROR_PROFILE_NAME_TOO_LONG",
|
|
@"Error message shown when user tries to update profile with a profile name "
|
|
@"that is too long.")];
|
|
return;
|
|
}
|
|
|
|
// Show an activity indicator to block the UI during the profile upload.
|
|
UIAlertController *alertController = [UIAlertController
|
|
alertControllerWithTitle:NSLocalizedString(@"PROFILE_VIEW_SAVING",
|
|
@"Alert title that indicates the user's profile view is being saved.")
|
|
message:nil
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
|
|
[self presentViewController:alertController
|
|
animated:YES
|
|
completion:^{
|
|
[OWSProfileManager.sharedManager updateLocalProfileName:normalizedProfileName
|
|
avatarImage:self.avatar
|
|
success:^{
|
|
[alertController dismissViewControllerAnimated:NO
|
|
completion:^{
|
|
[weakSelf updateProfileCompleted];
|
|
}];
|
|
}
|
|
failure:^{
|
|
[alertController
|
|
dismissViewControllerAnimated:NO
|
|
completion:^{
|
|
[OWSAlerts showErrorAlertWithMessage:
|
|
NSLocalizedString(
|
|
@"PROFILE_VIEW_ERROR_UPDATE_FAILED",
|
|
@"Error message shown when a "
|
|
@"profile update fails.")];
|
|
}];
|
|
}];
|
|
}];
|
|
}
|
|
|
|
- (NSString *)normalizedProfileName
|
|
{
|
|
return [self.nameTextField.text ows_stripped];
|
|
}
|
|
|
|
- (void)updateProfileCompleted
|
|
{
|
|
[self profileCompletedOrSkipped];
|
|
}
|
|
|
|
- (void)profileCompletedOrSkipped
|
|
{
|
|
// Dismiss this view.
|
|
switch (self.profileViewMode) {
|
|
case ProfileViewMode_AppSettings:
|
|
[self.navigationController popViewControllerAnimated:YES];
|
|
break;
|
|
case ProfileViewMode_Registration:
|
|
[self showHomeView];
|
|
break;
|
|
case ProfileViewMode_UpgradeOrNag:
|
|
[self dismissViewControllerAnimated:YES completion:nil];
|
|
break;
|
|
}
|
|
}
|
|
|
|
- (void)showHomeView
|
|
{
|
|
HomeViewController *homeView = [HomeViewController new];
|
|
SignalsNavigationController *navigationController =
|
|
[[SignalsNavigationController alloc] initWithRootViewController:homeView];
|
|
AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
|
|
appDelegate.window.rootViewController = navigationController;
|
|
OWSAssert([navigationController.topViewController isKindOfClass:[HomeViewController class]]);
|
|
}
|
|
|
|
#pragma mark - UITextFieldDelegate
|
|
|
|
- (BOOL)textField:(UITextField *)textField
|
|
shouldChangeCharactersInRange:(NSRange)editingRange
|
|
replacementString:(NSString *)insertionText
|
|
{
|
|
// TODO: Possibly filter invalid input.
|
|
return [TextFieldHelper textField:textField
|
|
shouldChangeCharactersInRange:editingRange
|
|
replacementString:insertionText
|
|
byteLimit:kOWSProfileManager_NameDataLength];
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField
|
|
{
|
|
[self updateProfile];
|
|
return NO;
|
|
}
|
|
|
|
- (void)textFieldDidChange:(id)sender
|
|
{
|
|
self.hasUnsavedChanges = YES;
|
|
|
|
// TODO: Update length warning.
|
|
}
|
|
|
|
#pragma mark - Avatar
|
|
|
|
- (void)setAvatar:(nullable UIImage *)avatar
|
|
{
|
|
OWSAssertIsOnMainThread();
|
|
|
|
_avatar = avatar;
|
|
|
|
self.hasUnsavedChanges = YES;
|
|
|
|
[self updateAvatarView];
|
|
}
|
|
|
|
- (void)updateAvatarView
|
|
{
|
|
self.avatarView.image = (self.avatar
|
|
?: [[UIImage imageNamed:@"profile_avatar_default"]
|
|
imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]);
|
|
self.avatarView.tintColor = (self.avatar ? nil : [UIColor colorWithRGBHex:0x888888]);
|
|
self.cameraImageView.hidden = self.avatar != nil;
|
|
}
|
|
|
|
- (void)nameRowTapped:(UIGestureRecognizer *)sender
|
|
{
|
|
if (sender.state == UIGestureRecognizerStateRecognized) {
|
|
[self.nameTextField becomeFirstResponder];
|
|
}
|
|
}
|
|
|
|
- (void)avatarRowTapped:(UIGestureRecognizer *)sender
|
|
{
|
|
if (sender.state == UIGestureRecognizerStateRecognized) {
|
|
[self avatarTapped];
|
|
}
|
|
}
|
|
|
|
- (void)infoRowTapped:(UIGestureRecognizer *)sender
|
|
{
|
|
if (sender.state == UIGestureRecognizerStateRecognized) {
|
|
[UIApplication.sharedApplication
|
|
openURL:[NSURL URLWithString:@"https://support.signal.org/hc/en-us/articles/115001110511"]];
|
|
}
|
|
}
|
|
|
|
- (void)saveButtonPressed
|
|
{
|
|
[self updatePressed];
|
|
}
|
|
|
|
#pragma mark - AvatarViewHelperDelegate
|
|
|
|
+ (BOOL)shouldDisplayProfileViewOnLaunch
|
|
{
|
|
// Only nag until the user sets a profile _name_. Profile names are
|
|
// recommended; profile avatars are optional.
|
|
if ([OWSProfileManager sharedManager].localProfileName.length > 0) {
|
|
return NO;
|
|
}
|
|
|
|
// Use the OWSPrimaryStorage.dbReadWriteConnection for consistency with the writes above.
|
|
NSTimeInterval kProfileNagFrequency = kDayInterval * 30;
|
|
NSDate *_Nullable lastPresentedDate =
|
|
[[[OWSPrimaryStorage sharedManager] dbReadWriteConnection] dateForKey:kProfileView_LastPresentedDate
|
|
inCollection:kProfileView_Collection];
|
|
return (!lastPresentedDate || fabs([lastPresentedDate timeIntervalSinceNow]) > kProfileNagFrequency);
|
|
}
|
|
|
|
+ (void)presentForAppSettings:(UINavigationController *)navigationController
|
|
{
|
|
OWSAssert(navigationController);
|
|
OWSAssert([navigationController isKindOfClass:[OWSNavigationController class]]);
|
|
|
|
ProfileViewController *vc = [[ProfileViewController alloc] initWithMode:ProfileViewMode_AppSettings];
|
|
[navigationController pushViewController:vc animated:YES];
|
|
}
|
|
|
|
+ (void)presentForRegistration:(UINavigationController *)navigationController
|
|
{
|
|
OWSAssert(navigationController);
|
|
OWSAssert([navigationController isKindOfClass:[OWSNavigationController class]]);
|
|
|
|
ProfileViewController *vc = [[ProfileViewController alloc] initWithMode:ProfileViewMode_Registration];
|
|
[navigationController pushViewController:vc animated:YES];
|
|
}
|
|
|
|
+ (void)presentForUpgradeOrNag:(HomeViewController *)presentingController
|
|
{
|
|
OWSAssert(presentingController);
|
|
|
|
ProfileViewController *vc = [[ProfileViewController alloc] initWithMode:ProfileViewMode_UpgradeOrNag];
|
|
OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:vc];
|
|
[presentingController presentTopLevelModalViewController:navigationController
|
|
animateDismissal:YES
|
|
animatePresentation:YES];
|
|
}
|
|
|
|
#pragma mark - AvatarViewHelperDelegate
|
|
|
|
- (NSString *)avatarActionSheetTitle
|
|
{
|
|
return NSLocalizedString(
|
|
@"PROFILE_VIEW_AVATAR_ACTIONSHEET_TITLE", @"Action Sheet title prompting the user for a profile avatar");
|
|
}
|
|
|
|
- (void)avatarDidChange:(UIImage *)image
|
|
{
|
|
OWSAssertIsOnMainThread();
|
|
OWSAssert(image);
|
|
|
|
self.avatar = [image resizedImageToFillPixelSize:CGSizeMake(kOWSProfileManager_MaxAvatarDiameter,
|
|
kOWSProfileManager_MaxAvatarDiameter)];
|
|
}
|
|
|
|
- (UIViewController *)fromViewController
|
|
{
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)hasClearAvatarAction
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (NSString *)clearAvatarActionLabel
|
|
{
|
|
return NSLocalizedString(@"PROFILE_VIEW_CLEAR_AVATAR", @"Label for action that clear's the user's profile avatar");
|
|
}
|
|
|
|
- (void)clearAvatar
|
|
{
|
|
self.avatar = nil;
|
|
}
|
|
|
|
#pragma mark - OWSNavigationView
|
|
|
|
- (BOOL)shouldCancelNavigationBack
|
|
{
|
|
BOOL result = self.hasUnsavedChanges;
|
|
if (result) {
|
|
[self backOrSkipButtonPressed];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@end
|
|
|
|
NS_ASSUME_NONNULL_END
|