Merge branch 'charlesmchen/profileView2'
This commit is contained in:
commit
83a02536a4
@ -65,7 +65,7 @@
|
||||
34B3F88D1E8DF1700035BE1A /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8631E8DF1700035BE1A /* OWSQRCodeScanningViewController.m */; };
|
||||
34B3F88E1E8DF1700035BE1A /* PrivacySettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8651E8DF1700035BE1A /* PrivacySettingsTableViewController.m */; };
|
||||
34B3F88F1E8DF1710035BE1A /* RegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8671E8DF1700035BE1A /* RegistrationViewController.m */; };
|
||||
34B3F8901E8DF1710035BE1A /* SettingsTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8691E8DF1700035BE1A /* SettingsTableViewController.m */; };
|
||||
34B3F8901E8DF1710035BE1A /* AppSettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8691E8DF1700035BE1A /* AppSettingsViewController.m */; };
|
||||
34B3F8911E8DF1710035BE1A /* ShowGroupMembersViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86B1E8DF1700035BE1A /* ShowGroupMembersViewController.m */; };
|
||||
34B3F8921E8DF1710035BE1A /* SignalAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86C1E8DF1700035BE1A /* SignalAttachment.swift */; };
|
||||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F86E1E8DF1700035BE1A /* SignalsNavigationController.m */; };
|
||||
@ -76,8 +76,9 @@
|
||||
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B3F8A11E8EA6040035BE1A /* ViewControllerUtils.m */; };
|
||||
34CCAF381F0C0599004084F4 /* AppUpdateNag.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF371F0C0599004084F4 /* AppUpdateNag.m */; };
|
||||
34CCAF3B1F0C2748004084F4 /* OWSAddToContactViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */; };
|
||||
34CE88E71F2FB9A10098030F /* ProfileViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34CE88E61F2FB9A10098030F /* ProfileViewController.m */; };
|
||||
34D5CC961EA6AFAD005515DB /* OWSContactsSyncing.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CC951EA6AFAD005515DB /* OWSContactsSyncing.m */; };
|
||||
34D5CCA91EAE3D30005515DB /* GroupViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* GroupViewHelper.m */; };
|
||||
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
|
||||
34D5CCB11EAE7E7F005515DB /* SelectRecipientViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCB01EAE7E7F005515DB /* SelectRecipientViewController.m */; };
|
||||
34D8C0271ED3673300188D7C /* DebugUIMessages.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0241ED3673300188D7C /* DebugUIMessages.m */; };
|
||||
34D8C0281ED3673300188D7C /* DebugUITableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D8C0261ED3673300188D7C /* DebugUITableViewController.m */; };
|
||||
@ -483,8 +484,8 @@
|
||||
34B3F8651E8DF1700035BE1A /* PrivacySettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrivacySettingsTableViewController.m; sourceTree = "<group>"; };
|
||||
34B3F8661E8DF1700035BE1A /* RegistrationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegistrationViewController.h; sourceTree = "<group>"; };
|
||||
34B3F8671E8DF1700035BE1A /* RegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RegistrationViewController.m; sourceTree = "<group>"; };
|
||||
34B3F8681E8DF1700035BE1A /* SettingsTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsTableViewController.h; sourceTree = "<group>"; };
|
||||
34B3F8691E8DF1700035BE1A /* SettingsTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsTableViewController.m; sourceTree = "<group>"; };
|
||||
34B3F8681E8DF1700035BE1A /* AppSettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppSettingsViewController.h; sourceTree = "<group>"; };
|
||||
34B3F8691E8DF1700035BE1A /* AppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppSettingsViewController.m; sourceTree = "<group>"; };
|
||||
34B3F86A1E8DF1700035BE1A /* ShowGroupMembersViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShowGroupMembersViewController.h; sourceTree = "<group>"; };
|
||||
34B3F86B1E8DF1700035BE1A /* ShowGroupMembersViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ShowGroupMembersViewController.m; sourceTree = "<group>"; };
|
||||
34B3F86C1E8DF1700035BE1A /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalAttachment.swift; sourceTree = "<group>"; };
|
||||
@ -503,12 +504,14 @@
|
||||
34CCAF371F0C0599004084F4 /* AppUpdateNag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppUpdateNag.m; sourceTree = "<group>"; };
|
||||
34CCAF391F0C2748004084F4 /* OWSAddToContactViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSAddToContactViewController.h; sourceTree = "<group>"; };
|
||||
34CCAF3A1F0C2748004084F4 /* OWSAddToContactViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSAddToContactViewController.m; sourceTree = "<group>"; };
|
||||
34CE88E51F2FB9A10098030F /* ProfileViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfileViewController.h; sourceTree = "<group>"; };
|
||||
34CE88E61F2FB9A10098030F /* ProfileViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProfileViewController.m; sourceTree = "<group>"; };
|
||||
34D5CC941EA6AFAD005515DB /* OWSContactsSyncing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactsSyncing.h; sourceTree = "<group>"; };
|
||||
34D5CC951EA6AFAD005515DB /* OWSContactsSyncing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactsSyncing.m; sourceTree = "<group>"; };
|
||||
34D5CC981EA6EB79005515DB /* OWSMessageCollectionViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageCollectionViewCell.h; sourceTree = "<group>"; };
|
||||
34D5CC9B1EA6ED17005515DB /* OWSMessageMediaAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageMediaAdapter.h; sourceTree = "<group>"; };
|
||||
34D5CCA71EAE3D30005515DB /* GroupViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GroupViewHelper.h; sourceTree = "<group>"; };
|
||||
34D5CCA81EAE3D30005515DB /* GroupViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GroupViewHelper.m; sourceTree = "<group>"; };
|
||||
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = "<group>"; };
|
||||
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = "<group>"; };
|
||||
34D5CCAB1EAE7136005515DB /* OWSConversationSettingsViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSConversationSettingsViewDelegate.h; sourceTree = "<group>"; };
|
||||
34D5CCAF1EAE7E7F005515DB /* SelectRecipientViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectRecipientViewController.h; sourceTree = "<group>"; };
|
||||
34D5CCB01EAE7E7F005515DB /* SelectRecipientViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SelectRecipientViewController.m; sourceTree = "<group>"; };
|
||||
@ -950,9 +953,13 @@
|
||||
3472229E1EB22FFE00E53955 /* AddToGroupViewController.m */,
|
||||
34B3F8361E8DF1700035BE1A /* AdvancedSettingsTableViewController.h */,
|
||||
34B3F8371E8DF1700035BE1A /* AdvancedSettingsTableViewController.m */,
|
||||
34B3F8681E8DF1700035BE1A /* AppSettingsViewController.h */,
|
||||
34B3F8691E8DF1700035BE1A /* AppSettingsViewController.m */,
|
||||
34B3F8381E8DF1700035BE1A /* AttachmentApprovalViewController.swift */,
|
||||
34B3F8391E8DF1700035BE1A /* AttachmentSharing.h */,
|
||||
34B3F83A1E8DF1700035BE1A /* AttachmentSharing.m */,
|
||||
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */,
|
||||
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */,
|
||||
343D3D991E9283F100165CA4 /* BlockListUIUtils.h */,
|
||||
343D3D9A1E9283F100165CA4 /* BlockListUIUtils.m */,
|
||||
34B3F89A1E8DF3270035BE1A /* BlockListViewController.h */,
|
||||
@ -977,8 +984,6 @@
|
||||
34E8BF371EE9E2FD00F5F4CA /* FingerprintViewScanController.m */,
|
||||
34B3F8471E8DF1700035BE1A /* FullImageViewController.h */,
|
||||
34B3F8481E8DF1700035BE1A /* FullImageViewController.m */,
|
||||
34D5CCA71EAE3D30005515DB /* GroupViewHelper.h */,
|
||||
34D5CCA81EAE3D30005515DB /* GroupViewHelper.m */,
|
||||
34B3F8491E8DF1700035BE1A /* InboxTableViewCell.h */,
|
||||
34B3F84A1E8DF1700035BE1A /* InboxTableViewCell.m */,
|
||||
34B3F84C1E8DF1700035BE1A /* InviteFlow.swift */,
|
||||
@ -1017,6 +1022,8 @@
|
||||
34D99C8B1F27B13B00D284D6 /* OWSViewController.m */,
|
||||
34B3F8641E8DF1700035BE1A /* PrivacySettingsTableViewController.h */,
|
||||
34B3F8651E8DF1700035BE1A /* PrivacySettingsTableViewController.m */,
|
||||
34CE88E51F2FB9A10098030F /* ProfileViewController.h */,
|
||||
34CE88E61F2FB9A10098030F /* ProfileViewController.m */,
|
||||
34B3F8661E8DF1700035BE1A /* RegistrationViewController.h */,
|
||||
34B3F8671E8DF1700035BE1A /* RegistrationViewController.m */,
|
||||
4585C4671ED8F8D200896AEA /* SafetyNumberConfirmationAlert.swift */,
|
||||
@ -1026,8 +1033,6 @@
|
||||
3400C7951EAF99F4008A8584 /* SelectThreadViewController.m */,
|
||||
3400C7901EAF89CD008A8584 /* SendExternalFileViewController.h */,
|
||||
3400C7911EAF89CD008A8584 /* SendExternalFileViewController.m */,
|
||||
34B3F8681E8DF1700035BE1A /* SettingsTableViewController.h */,
|
||||
34B3F8691E8DF1700035BE1A /* SettingsTableViewController.m */,
|
||||
34B3F86A1E8DF1700035BE1A /* ShowGroupMembersViewController.h */,
|
||||
34B3F86B1E8DF1700035BE1A /* ShowGroupMembersViewController.m */,
|
||||
34B3F86C1E8DF1700035BE1A /* SignalAttachment.swift */,
|
||||
@ -2161,12 +2166,13 @@
|
||||
34D5CCB11EAE7E7F005515DB /* SelectRecipientViewController.m in Sources */,
|
||||
34B3F88F1E8DF1710035BE1A /* RegistrationViewController.m in Sources */,
|
||||
3448BFCD1EDF0EA7005B2D69 /* OWSMessagesInputToolbar.m in Sources */,
|
||||
34B3F8901E8DF1710035BE1A /* SettingsTableViewController.m in Sources */,
|
||||
34B3F8901E8DF1710035BE1A /* AppSettingsViewController.m in Sources */,
|
||||
34FD93701E3BD43A00109093 /* OWSAnyTouchGestureRecognizer.m in Sources */,
|
||||
343D3D9B1E9283F100165CA4 /* BlockListUIUtils.m in Sources */,
|
||||
34B3F8931E8DF1710035BE1A /* SignalsNavigationController.m in Sources */,
|
||||
76EB063A18170B33006006FC /* FunctionalUtil.m in Sources */,
|
||||
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */,
|
||||
34CE88E71F2FB9A10098030F /* ProfileViewController.m in Sources */,
|
||||
348F2EAE1F0D21BC00D4ECE0 /* DeviceSleepManager.swift in Sources */,
|
||||
34E3EF101EFC2684007F6822 /* DebugUIPage.m in Sources */,
|
||||
76EB058A18170B33006006FC /* Release.m in Sources */,
|
||||
@ -2216,7 +2222,7 @@
|
||||
34B3F8881E8DF1700035BE1A /* OversizeTextMessageViewController.swift in Sources */,
|
||||
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
|
||||
34B3F8A21E8EA6040035BE1A /* ViewControllerUtils.m in Sources */,
|
||||
34D5CCA91EAE3D30005515DB /* GroupViewHelper.m in Sources */,
|
||||
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
|
||||
453D28BA1D332DB100D523F0 /* OWSMessagesBubblesSizeCalculator.m in Sources */,
|
||||
45F170AC1E2F0351003FC1F2 /* CallAudioSession.swift in Sources */,
|
||||
34B3F8801E8DF1700035BE1A /* InviteFlow.swift in Sources */,
|
||||
|
||||
23
Signal/Images.xcassets/profile_avatar_default.imageset/Contents.json
vendored
Normal file
23
Signal/Images.xcassets/profile_avatar_default.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "profile_avatar_default@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "profile_avatar_default@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "profile_avatar_default@3x.png",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png
vendored
Normal file
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@1x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png
vendored
Normal file
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png
vendored
Normal file
BIN
Signal/Images.xcassets/profile_avatar_default.imageset/profile_avatar_default@3x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
@ -28,6 +28,7 @@
|
||||
#import <SignalServiceKit/OWSFailedMessagesJob.h>
|
||||
#import <SignalServiceKit/OWSIncomingMessageReadObserver.h>
|
||||
#import <SignalServiceKit/OWSMessageSender.h>
|
||||
#import <SignalServiceKit/OWSProfilesManager.h>
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSDatabaseView.h>
|
||||
#import <SignalServiceKit/TSMessagesManager.h>
|
||||
@ -160,6 +161,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
||||
DDLogInfo(@"%@ application: didFinishLaunchingWithOptions completed.", self.tag);
|
||||
|
||||
[OWSAnalytics appLaunchDidBegin];
|
||||
[OWSProfilesManager.sharedManager appLaunchDidBegin];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "AppSettingsViewController.h"
|
||||
#import "AttachmentSharing.h"
|
||||
#import "Environment.h"
|
||||
#import "FLAnimatedImage.h"
|
||||
@ -23,7 +24,6 @@
|
||||
#import "PrivacySettingsTableViewController.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "PushManager.h"
|
||||
#import "SettingsTableViewController.h"
|
||||
#import "SignalsViewController.h"
|
||||
#import "TSMessageAdapter.h"
|
||||
#import "UIColor+OWS.h"
|
||||
|
||||
@ -4,6 +4,6 @@
|
||||
|
||||
#import "OWSTableViewController.h"
|
||||
|
||||
@interface SettingsTableViewController : OWSTableViewController
|
||||
@interface AppSettingsViewController : OWSTableViewController
|
||||
|
||||
@end
|
||||
@ -2,7 +2,7 @@
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsTableViewController.h"
|
||||
#import "AppSettingsViewController.h"
|
||||
#import "AboutTableViewController.h"
|
||||
#import "AdvancedSettingsTableViewController.h"
|
||||
#import "DebugUITableViewController.h"
|
||||
@ -11,6 +11,7 @@
|
||||
#import "OWSContactsManager.h"
|
||||
#import "OWSLinkedDevicesTableViewController.h"
|
||||
#import "PrivacySettingsTableViewController.h"
|
||||
#import "ProfileViewController.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "PushManager.h"
|
||||
#import "Signal-Swift.h"
|
||||
@ -18,7 +19,7 @@
|
||||
#import <SignalServiceKit/TSAccountManager.h>
|
||||
#import <SignalServiceKit/TSSocketManager.h>
|
||||
|
||||
@interface SettingsTableViewController ()
|
||||
@interface AppSettingsViewController ()
|
||||
|
||||
@property (nonatomic, readonly) OWSContactsManager *contactsManager;
|
||||
|
||||
@ -26,7 +27,7 @@
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SettingsTableViewController
|
||||
@implementation AppSettingsViewController
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
@ -72,7 +73,7 @@
|
||||
[self observeNotifications];
|
||||
|
||||
self.title = NSLocalizedString(@"SETTINGS_NAV_BAR_TITLE", @"Title for settings activity");
|
||||
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
@ -83,7 +84,8 @@
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
@ -94,7 +96,7 @@
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
OWSTableSection *section = [OWSTableSection new];
|
||||
|
||||
__weak SettingsTableViewController *weakSelf = self;
|
||||
__weak AppSettingsViewController *weakSelf = self;
|
||||
[section addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
cell.preservesSuperviewLayoutMargins = YES;
|
||||
@ -168,6 +170,13 @@
|
||||
}
|
||||
actionBlock:nil]];
|
||||
}
|
||||
|
||||
[section addItem:[OWSTableItem
|
||||
disclosureItemWithText:NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view.")
|
||||
actionBlock:^{
|
||||
[weakSelf showProfile];
|
||||
}]];
|
||||
|
||||
[section addItem:[OWSTableItem disclosureItemWithText:NSLocalizedString(@"SETTINGS_INVITE_TITLE",
|
||||
@"Settings table view cell label")
|
||||
actionBlock:^{
|
||||
@ -225,7 +234,7 @@
|
||||
actionBlock:nil]];
|
||||
|
||||
[contents addSection:section];
|
||||
|
||||
|
||||
self.contents = contents;
|
||||
}
|
||||
|
||||
@ -255,6 +264,12 @@
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)showProfile
|
||||
{
|
||||
ProfileViewController *vc = [[ProfileViewController alloc] init];
|
||||
[self.navigationController pushViewController:vc animated:YES];
|
||||
}
|
||||
|
||||
- (void)showAdvanced
|
||||
{
|
||||
AdvancedSettingsTableViewController *vc = [[AdvancedSettingsTableViewController alloc] init];
|
||||
@ -288,7 +303,7 @@
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"PROCEED_BUTTON", @"")
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self proceedToUnregistration];
|
||||
[self proceedToUnregistration];
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
||||
style:UIAlertActionStyleCancel
|
||||
@ -297,7 +312,8 @@
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)proceedToUnregistration {
|
||||
- (void)proceedToUnregistration
|
||||
{
|
||||
[TSAccountManager unregisterTextSecureWithSuccess:^{
|
||||
[Environment resetAppData];
|
||||
}
|
||||
@ -316,9 +332,10 @@
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)socketStateDidChange {
|
||||
- (void)socketStateDidChange
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
36
Signal/src/ViewControllers/AvatarViewHelper.h
Normal file
36
Signal/src/ViewControllers/AvatarViewHelper.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAccount;
|
||||
@class AvatarViewHelper;
|
||||
@class OWSContactsManager;
|
||||
@class TSThread;
|
||||
|
||||
@protocol AvatarViewHelperDelegate <NSObject>
|
||||
|
||||
- (NSString *)avatarActionSheetTitle;
|
||||
|
||||
- (void)avatarDidChange:(UIImage *)image;
|
||||
|
||||
- (UIViewController *)fromViewController;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef void (^AvatarViewSuccessBlock)();
|
||||
|
||||
@interface AvatarViewHelper : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<AvatarViewHelperDelegate> delegate;
|
||||
|
||||
- (void)showChangeAvatarUI;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -2,7 +2,7 @@
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "GroupViewHelper.h"
|
||||
#import "AvatarViewHelper.h"
|
||||
#import "OWSContactsManager.h"
|
||||
#import "UIUtil.h"
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
@ -13,24 +13,23 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface GroupViewHelper () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
|
||||
@interface AvatarViewHelper () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation GroupViewHelper
|
||||
@implementation AvatarViewHelper
|
||||
|
||||
#pragma mark - Group Avatar
|
||||
#pragma mark - Avatar Avatar
|
||||
|
||||
- (void)showChangeGroupAvatarUI
|
||||
- (void)showChangeAvatarUI
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(self.delegate);
|
||||
|
||||
UIAlertController *actionSheetController =
|
||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"NEW_GROUP_ADD_PHOTO_ACTION",
|
||||
@"Action Sheet title prompting the user for a group avatar")
|
||||
[UIAlertController alertControllerWithTitle:self.delegate.avatarActionSheetTitle
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"")
|
||||
@ -119,7 +118,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
//
|
||||
// See: GroupCreateActivity.java in Signal-Android.java.
|
||||
UIImage *resizedAvatar = [rawAvatar resizedImageToFillPixelSize:CGSizeMake(210, 210)];
|
||||
[self.delegate groupAvatarDidChange:resizedAvatar];
|
||||
[self.delegate avatarDidChange:resizedAvatar];
|
||||
}
|
||||
|
||||
[self.delegate.fromViewController dismissViewControllerAnimated:YES completion:nil];
|
||||
@ -900,7 +900,7 @@ class CallViewController: OWSViewController, CallObserver, CallServiceObserver,
|
||||
assert(fromViewController != nil)
|
||||
|
||||
// Construct the "settings" view & push the "privacy settings" view.
|
||||
let navigationController = UINavigationController(rootViewController:SettingsTableViewController())
|
||||
let navigationController = UINavigationController(rootViewController:AppSettingsViewController())
|
||||
navigationController.pushViewController(PrivacySettingsTableViewController(), animated:false)
|
||||
|
||||
fromViewController?.present(navigationController, animated: true, completion: nil)
|
||||
|
||||
@ -38,7 +38,7 @@ private class CallKitExperienceUpgradeViewController: ExperienceUpgradeViewContr
|
||||
assert(fromViewController != nil)
|
||||
|
||||
// Construct the "settings" view & push the "privacy settings" view.
|
||||
let navigationController = UINavigationController(rootViewController:SettingsTableViewController())
|
||||
let navigationController = UINavigationController(rootViewController:AppSettingsViewController())
|
||||
navigationController.pushViewController(PrivacySettingsTableViewController(), animated:false)
|
||||
|
||||
fromViewController?.present(navigationController, animated: true, completion: nil)
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAccount;
|
||||
@class GroupViewHelper;
|
||||
@class OWSContactsManager;
|
||||
@class TSThread;
|
||||
|
||||
@protocol GroupViewHelperDelegate <NSObject>
|
||||
|
||||
- (void)groupAvatarDidChange:(UIImage *)image;
|
||||
|
||||
- (UIViewController *)fromViewController;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
typedef void (^GroupViewSuccessBlock)();
|
||||
|
||||
@interface GroupViewHelper : NSObject
|
||||
|
||||
@property (nonatomic, weak) id<GroupViewHelperDelegate> delegate;
|
||||
|
||||
- (void)showChangeGroupAvatarUI;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -4,11 +4,11 @@
|
||||
|
||||
#import "NewGroupViewController.h"
|
||||
#import "AddToGroupViewController.h"
|
||||
#import "AvatarViewHelper.h"
|
||||
#import "BlockListUIUtils.h"
|
||||
#import "ContactTableViewCell.h"
|
||||
#import "ContactsViewHelper.h"
|
||||
#import "Environment.h"
|
||||
#import "GroupViewHelper.h"
|
||||
#import "OWSContactsManager.h"
|
||||
#import "OWSTableViewController.h"
|
||||
#import "Signal-Swift.h"
|
||||
@ -31,14 +31,14 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
|
||||
@interface NewGroupViewController () <UIImagePickerControllerDelegate,
|
||||
UITextFieldDelegate,
|
||||
ContactsViewHelperDelegate,
|
||||
GroupViewHelperDelegate,
|
||||
AvatarViewHelperDelegate,
|
||||
AddToGroupViewControllerDelegate,
|
||||
OWSTableViewControllerDelegate,
|
||||
UINavigationControllerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
|
||||
@property (nonatomic, readonly) GroupViewHelper *groupViewHelper;
|
||||
@property (nonatomic, readonly) AvatarViewHelper *avatarViewHelper;
|
||||
|
||||
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
|
||||
@property (nonatomic, readonly) AvatarImageView *avatarView;
|
||||
@ -84,8 +84,8 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
|
||||
{
|
||||
_messageSender = [Environment getCurrent].messageSender;
|
||||
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];
|
||||
_groupViewHelper = [GroupViewHelper new];
|
||||
_groupViewHelper.delegate = self;
|
||||
_avatarViewHelper = [AvatarViewHelper new];
|
||||
_avatarViewHelper.delegate = self;
|
||||
|
||||
self.memberRecipientIds = [NSMutableSet new];
|
||||
}
|
||||
@ -181,7 +181,7 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
|
||||
- (void)avatarTouched:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state == UIGestureRecognizerStateRecognized) {
|
||||
[self showChangeGroupAvatarUI];
|
||||
[self showChangeAvatarUI];
|
||||
}
|
||||
}
|
||||
|
||||
@ -520,9 +520,9 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
|
||||
|
||||
#pragma mark - Group Avatar
|
||||
|
||||
- (void)showChangeGroupAvatarUI
|
||||
- (void)showChangeAvatarUI
|
||||
{
|
||||
[self.groupViewHelper showChangeGroupAvatarUI];
|
||||
[self.avatarViewHelper showChangeAvatarUI];
|
||||
}
|
||||
|
||||
- (void)setGroupAvatar:(nullable UIImage *)groupAvatar
|
||||
@ -606,9 +606,15 @@ const NSUInteger kNewGroupViewControllerAvatarWidth = 68;
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - GroupViewHelperDelegate
|
||||
#pragma mark - AvatarViewHelperDelegate
|
||||
|
||||
- (void)groupAvatarDidChange:(UIImage *)image
|
||||
- (NSString *)avatarActionSheetTitle
|
||||
{
|
||||
return NSLocalizedString(
|
||||
@"NEW_GROUP_ADD_PHOTO_ACTION", @"Action Sheet title prompting the user for a group avatar");
|
||||
}
|
||||
|
||||
- (void)avatarDidChange:(UIImage *)image
|
||||
{
|
||||
OWSAssert(image);
|
||||
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
#import "OWSLinkDeviceViewController.h"
|
||||
#import "OWSDeviceProvisioningURLParser.h"
|
||||
#import "OWSLinkedDevicesTableViewController.h"
|
||||
#import "SettingsTableViewController.h"
|
||||
#import <SignalServiceKit/ECKeyPair+OWSPrivateKey.h>
|
||||
#import <SignalServiceKit/OWSDeviceProvisioner.h>
|
||||
#import <SignalServiceKit/OWSIdentityManager.h>
|
||||
|
||||
13
Signal/src/ViewControllers/ProfileViewController.h
Normal file
13
Signal/src/ViewControllers/ProfileViewController.h
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSTableViewController.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ProfileViewController : OWSTableViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
306
Signal/src/ViewControllers/ProfileViewController.m
Normal file
306
Signal/src/ViewControllers/ProfileViewController.m
Normal file
@ -0,0 +1,306 @@
|
||||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ProfileViewController.h"
|
||||
#import "AvatarViewHelper.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import "UIViewController+OWS.h"
|
||||
#import <SignalServiceKit/OWSProfilesManager.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface ProfileViewController () <UITextFieldDelegate, AvatarViewHelperDelegate>
|
||||
|
||||
@property (nonatomic, readonly) AvatarViewHelper *avatarViewHelper;
|
||||
|
||||
@property (nonatomic) UITextField *nameTextField;
|
||||
|
||||
@property (nonatomic) AvatarImageView *avatarView;
|
||||
|
||||
@property (nonatomic) UILabel *avatarLabel;
|
||||
|
||||
@property (nonatomic, nullable) UIImage *avatar;
|
||||
|
||||
@property (nonatomic) BOOL hasUnsavedChanges;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation ProfileViewController
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
self.view.backgroundColor = [UIColor whiteColor];
|
||||
[self.navigationController.navigationBar setTranslucent:NO];
|
||||
self.title = NSLocalizedString(@"PROFILE_VIEW_TITLE", @"Title for the profile view.");
|
||||
self.navigationItem.leftBarButtonItem =
|
||||
[self createOWSBackButtonWithTarget:self selector:@selector(backButtonPressed:)];
|
||||
|
||||
_avatarViewHelper = [AvatarViewHelper new];
|
||||
_avatarViewHelper.delegate = self;
|
||||
|
||||
_avatar = [OWSProfilesManager.sharedManager localProfileAvatarImage];
|
||||
|
||||
[self createViews];
|
||||
}
|
||||
|
||||
- (void)createViews
|
||||
{
|
||||
_nameTextField = [UITextField new];
|
||||
_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 = [OWSProfilesManager.sharedManager localProfileName];
|
||||
[_nameTextField addTarget:self action:@selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
|
||||
|
||||
_avatarView = [AvatarImageView new];
|
||||
|
||||
_avatarLabel = [UILabel new];
|
||||
_avatarLabel.font = [UIFont ows_regularFontWithSize:14.f];
|
||||
_avatarLabel.textColor = [UIColor ows_materialBlueColor];
|
||||
// TODO: Copy.
|
||||
_avatarLabel.text
|
||||
= NSLocalizedString(@"PROFILE_VIEW_AVATAR_INSTRUCTIONS", @"Instructions for how to change the profile avatar.");
|
||||
[_avatarLabel sizeToFit];
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - Table Contents
|
||||
|
||||
- (void)updateTableContents
|
||||
{
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
|
||||
__weak ProfileViewController *weakSelf = self;
|
||||
|
||||
// Profile Avatar
|
||||
OWSTableSection *avatarSection = [OWSTableSection new];
|
||||
avatarSection.headerTitle = NSLocalizedString(
|
||||
@"PROFILE_VIEW_AVATAR_SECTION_HEADER", @"Header title for the profile avatar field of the profile view.");
|
||||
const CGFloat kAvatarSizePoints = 100.f;
|
||||
const CGFloat kAvatarTopMargin = 10.f;
|
||||
const CGFloat kAvatarBottomMargin = 10.f;
|
||||
const CGFloat kAvatarVSpacing = 10.f;
|
||||
CGFloat avatarCellHeight
|
||||
= round(kAvatarSizePoints + kAvatarTopMargin + kAvatarBottomMargin + kAvatarVSpacing + self.avatarLabel.height);
|
||||
[avatarSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
cell.preservesSuperviewLayoutMargins = YES;
|
||||
cell.contentView.preservesSuperviewLayoutMargins = YES;
|
||||
|
||||
AvatarImageView *avatarView = weakSelf.avatarView;
|
||||
[weakSelf updateAvatarView];
|
||||
[cell.contentView addSubview:avatarView];
|
||||
[avatarView autoHCenterInSuperview];
|
||||
[avatarView autoPinEdgeToSuperviewEdge:ALEdgeTop withInset:kAvatarTopMargin];
|
||||
[avatarView autoSetDimension:ALDimensionWidth toSize:kAvatarSizePoints];
|
||||
[avatarView autoSetDimension:ALDimensionHeight toSize:kAvatarSizePoints];
|
||||
|
||||
UILabel *avatarLabel = weakSelf.avatarLabel;
|
||||
[cell.contentView addSubview:avatarLabel];
|
||||
[avatarLabel autoHCenterInSuperview];
|
||||
[avatarLabel autoPinEdgeToSuperviewEdge:ALEdgeBottom withInset:kAvatarBottomMargin];
|
||||
|
||||
cell.userInteractionEnabled = YES;
|
||||
[cell
|
||||
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(avatarTapped:)]];
|
||||
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
return cell;
|
||||
}
|
||||
customRowHeight:avatarCellHeight
|
||||
actionBlock:nil]];
|
||||
[contents addSection:avatarSection];
|
||||
|
||||
// Profile Name
|
||||
OWSTableSection *nameSection = [OWSTableSection new];
|
||||
nameSection.headerTitle = NSLocalizedString(
|
||||
@"PROFILE_VIEW_NAME_SECTION_HEADER", @"Label for the profile name field of the profile view.");
|
||||
[nameSection
|
||||
addItem:
|
||||
[OWSTableItem
|
||||
itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
cell.preservesSuperviewLayoutMargins = YES;
|
||||
cell.contentView.preservesSuperviewLayoutMargins = YES;
|
||||
|
||||
UITextField *nameTextField = weakSelf.nameTextField;
|
||||
[cell.contentView addSubview:nameTextField];
|
||||
[nameTextField autoPinLeadingToSuperView];
|
||||
[nameTextField autoPinTrailingToSuperView];
|
||||
[nameTextField autoVCenterInSuperview];
|
||||
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
return cell;
|
||||
}
|
||||
actionBlock:nil]];
|
||||
[contents addSection:nameSection];
|
||||
|
||||
self.contents = contents;
|
||||
}
|
||||
|
||||
#pragma mark - Event Handling
|
||||
|
||||
- (void)backButtonPressed:(id)sender
|
||||
{
|
||||
[self.nameTextField resignFirstResponder];
|
||||
|
||||
if (!self.hasUnsavedChanges) {
|
||||
// If user made no changes, return to conversation settings view.
|
||||
[self.navigationController popViewControllerAnimated:YES];
|
||||
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.navigationController popViewControllerAnimated:YES];
|
||||
}]];
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", nil)
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
[self presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)avatarTapped:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state == UIGestureRecognizerStateRecognized) {
|
||||
[self.avatarViewHelper showChangeAvatarUI];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHasUnsavedChanges:(BOOL)hasUnsavedChanges
|
||||
{
|
||||
_hasUnsavedChanges = hasUnsavedChanges;
|
||||
|
||||
if (hasUnsavedChanges) {
|
||||
self.navigationItem.rightBarButtonItem = (self.hasUnsavedChanges
|
||||
? [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"EDIT_GROUP_UPDATE_BUTTON",
|
||||
@"The title for the 'update group' button.")
|
||||
style:UIBarButtonItemStylePlain
|
||||
target:self
|
||||
action:@selector(updatePressed)]
|
||||
: nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)updatePressed
|
||||
{
|
||||
[self updateProfile];
|
||||
}
|
||||
|
||||
- (void)updateProfile
|
||||
{
|
||||
__weak ProfileViewController *weakSelf = self;
|
||||
[OWSProfilesManager.sharedManager
|
||||
updateLocalProfileName:self.nameTextField.text
|
||||
localProfileAvatarImage:self.avatar
|
||||
success:^{
|
||||
[weakSelf.navigationController popViewControllerAnimated:YES];
|
||||
}
|
||||
failure:^{
|
||||
// <#code#>
|
||||
}];
|
||||
}
|
||||
|
||||
#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
|
||||
{
|
||||
// TODO: Possibly filter invalid input.
|
||||
// TODO: Possibly prevent user from typing overlong name.
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (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
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
_avatar = avatar;
|
||||
|
||||
self.hasUnsavedChanges = YES;
|
||||
|
||||
[self updateAvatarView];
|
||||
}
|
||||
|
||||
- (void)updateAvatarView
|
||||
{
|
||||
self.avatarView.image = (self.avatar ?: [UIImage imageNamed:@"profile_avatar_default"]);
|
||||
}
|
||||
|
||||
#pragma mark - AvatarViewHelperDelegate
|
||||
|
||||
- (NSString *)avatarActionSheetTitle
|
||||
{
|
||||
return NSLocalizedString(
|
||||
@"PROFILE_AVATAR_ACTIONSHEET_TITLE", @"Action Sheet title prompting the user for a profile avatar");
|
||||
}
|
||||
|
||||
- (void)avatarDidChange:(UIImage *)image
|
||||
{
|
||||
OWSAssert(image);
|
||||
|
||||
// TODO: Crop to square and possible resize.
|
||||
|
||||
self.avatar = image;
|
||||
}
|
||||
|
||||
- (UIViewController *)fromViewController
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Logging
|
||||
|
||||
+ (NSString *)tag
|
||||
{
|
||||
return [NSString stringWithFormat:@"[%@]", self.class];
|
||||
}
|
||||
|
||||
- (NSString *)tag
|
||||
{
|
||||
return self.class.tag;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
#import "SignalsViewController.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "AppSettingsViewController.h"
|
||||
#import "InboxTableViewCell.h"
|
||||
#import "MessageComposeTableViewController.h"
|
||||
#import "MessagesViewController.h"
|
||||
@ -11,7 +12,6 @@
|
||||
#import "OWSContactsManager.h"
|
||||
#import "PropertyListPreferences.h"
|
||||
#import "PushManager.h"
|
||||
#import "SettingsTableViewController.h"
|
||||
#import "Signal-Swift.h"
|
||||
#import "TSAccountManager.h"
|
||||
#import "TSDatabaseView.h"
|
||||
@ -305,7 +305,7 @@ typedef NS_ENUM(NSInteger, CellState) { kArchiveState, kInboxState };
|
||||
}
|
||||
|
||||
- (void)settingsButtonPressed:(id)sender {
|
||||
SettingsTableViewController *vc = [SettingsTableViewController new];
|
||||
AppSettingsViewController *vc = [AppSettingsViewController new];
|
||||
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc];
|
||||
[self presentViewController:navigationController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
@ -4,11 +4,11 @@
|
||||
|
||||
#import "UpdateGroupViewController.h"
|
||||
#import "AddToGroupViewController.h"
|
||||
#import "AvatarViewHelper.h"
|
||||
#import "BlockListUIUtils.h"
|
||||
#import "ContactTableViewCell.h"
|
||||
#import "ContactsViewHelper.h"
|
||||
#import "Environment.h"
|
||||
#import "GroupViewHelper.h"
|
||||
#import "OWSContactsManager.h"
|
||||
#import "OWSTableViewController.h"
|
||||
#import "Signal-Swift.h"
|
||||
@ -30,14 +30,14 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@interface UpdateGroupViewController () <UIImagePickerControllerDelegate,
|
||||
UITextFieldDelegate,
|
||||
ContactsViewHelperDelegate,
|
||||
GroupViewHelperDelegate,
|
||||
AvatarViewHelperDelegate,
|
||||
AddToGroupViewControllerDelegate,
|
||||
OWSTableViewControllerDelegate,
|
||||
UINavigationControllerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
|
||||
@property (nonatomic, readonly) GroupViewHelper *groupViewHelper;
|
||||
@property (nonatomic, readonly) AvatarViewHelper *avatarViewHelper;
|
||||
|
||||
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
|
||||
@property (nonatomic, readonly) AvatarImageView *avatarView;
|
||||
@ -83,8 +83,8 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
{
|
||||
_messageSender = [Environment getCurrent].messageSender;
|
||||
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];
|
||||
_groupViewHelper = [GroupViewHelper new];
|
||||
_groupViewHelper.delegate = self;
|
||||
_avatarViewHelper = [AvatarViewHelper new];
|
||||
_avatarViewHelper.delegate = self;
|
||||
|
||||
self.memberRecipientIds = [NSMutableSet new];
|
||||
}
|
||||
@ -158,7 +158,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
[self.groupNameTextField becomeFirstResponder];
|
||||
break;
|
||||
case UpdateGroupMode_EditGroupAvatar:
|
||||
[self showChangeGroupAvatarUI];
|
||||
[self showChangeAvatarUI];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -228,7 +228,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
- (void)avatarTouched:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state == UIGestureRecognizerStateRecognized) {
|
||||
[self showChangeGroupAvatarUI];
|
||||
[self showChangeAvatarUI];
|
||||
}
|
||||
}
|
||||
|
||||
@ -384,11 +384,11 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#pragma mark - Group Avatar
|
||||
|
||||
- (void)showChangeGroupAvatarUI
|
||||
- (void)showChangeAvatarUI
|
||||
{
|
||||
[self.groupNameTextField resignFirstResponder];
|
||||
|
||||
[self.groupViewHelper showChangeGroupAvatarUI];
|
||||
[self.avatarViewHelper showChangeAvatarUI];
|
||||
}
|
||||
|
||||
- (void)setGroupAvatar:(nullable UIImage *)groupAvatar
|
||||
@ -487,9 +487,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - GroupViewHelperDelegate
|
||||
#pragma mark - AvatarViewHelperDelegate
|
||||
|
||||
- (void)groupAvatarDidChange:(UIImage *)image
|
||||
- (NSString *)avatarActionSheetTitle
|
||||
{
|
||||
return NSLocalizedString(
|
||||
@"NEW_GROUP_ADD_PHOTO_ACTION", @"Action Sheet title prompting the user for a group avatar");
|
||||
}
|
||||
|
||||
- (void)avatarDidChange:(UIImage *)image
|
||||
{
|
||||
OWSAssert(image);
|
||||
|
||||
|
||||
@ -1036,6 +1036,24 @@
|
||||
/* No comment provided by engineer. */
|
||||
"PROCEED_BUTTON" = "Proceed";
|
||||
|
||||
/* Action Sheet title prompting the user for a profile avatar */
|
||||
"PROFILE_AVATAR_ACTIONSHEET_TITLE" = "Set Profile Avatar";
|
||||
|
||||
/* Instructions for how to change the profile avatar. */
|
||||
"PROFILE_VIEW_AVATAR_INSTRUCTIONS" = "Tap to Select Avatar";
|
||||
|
||||
/* Header title for the profile avatar field of the profile view. */
|
||||
"PROFILE_VIEW_AVATAR_SECTION_HEADER" = "Avatar";
|
||||
|
||||
/* Default text for the profile name field of the profile view. */
|
||||
"PROFILE_VIEW_NAME_DEFAULT_TEXT" = "Enter your name.";
|
||||
|
||||
/* Label for the profile name field of the profile view. */
|
||||
"PROFILE_VIEW_NAME_SECTION_HEADER" = "Profile Name";
|
||||
|
||||
/* Title for the profile view. */
|
||||
"PROFILE_VIEW_TITLE" = "Profile";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"PUSH_MANAGER_MARKREAD" = "Mark as Read";
|
||||
|
||||
|
||||
@ -314,7 +314,7 @@ NSString *const kNSNotificationName_LocalNumberDidChange = @"kNSNotificationName
|
||||
DDLogInfo(@"%@ Successfully unregistered", self.tag);
|
||||
success();
|
||||
|
||||
// This is called from `[SettingsTableViewController proceedToUnregistration]` whose
|
||||
// This is called from `[AppSettingsViewController proceedToUnregistration]` whose
|
||||
// success handler calls `[Environment resetAppData]`.
|
||||
// This method, after calling that success handler, fires
|
||||
// `kNSNotificationName_RegistrationStateDidChange` which is only safe to fire after
|
||||
|
||||
@ -167,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *documentsPath =
|
||||
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
attachmentsFolder = [documentsPath stringByAppendingFormat:@"/Attachments"];
|
||||
attachmentsFolder = [documentsPath stringByAppendingPathComponent:@"Attachments"];
|
||||
|
||||
BOOL isDirectory;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:attachmentsFolder isDirectory:&isDirectory];
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const kNSNotificationName_LocalProfileDidChange;
|
||||
|
||||
// This class can be safely accessed and used from any thread.
|
||||
@interface OWSProfilesManager : NSObject
|
||||
|
||||
@ -11,6 +13,19 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
@property (atomic, nullable, readonly) NSString *localProfileName;
|
||||
@property (atomic, nullable, readonly) UIImage *localProfileAvatarImage;
|
||||
|
||||
// This method is used to update the "local profile" state on the client
|
||||
// and the service. Client state is only updated if service state is
|
||||
// successfully updated.
|
||||
- (void)updateLocalProfileName:(nullable NSString *)localProfileName
|
||||
localProfileAvatarImage:(nullable UIImage *)localProfileAvatarImage
|
||||
success:(void (^)())successBlock
|
||||
failure:(void (^)())failureBlock;
|
||||
|
||||
- (void)appLaunchDidBegin;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@ -8,11 +8,79 @@
|
||||
#import "TSStorageManager.h"
|
||||
#import "TextSecureKitEnv.h"
|
||||
|
||||
#import "TSYapDatabaseObject.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSThread;
|
||||
|
||||
@interface AvatarMetadata : TSYapDatabaseObject
|
||||
|
||||
// This filename is relative to OWSProfilesManager.profileAvatarsDirPath.
|
||||
@property (nonatomic, readonly) NSString *fileName;
|
||||
@property (nonatomic, readonly) NSString *avatarUrl;
|
||||
@property (nonatomic, readonly) NSString *avatarDigest;
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation AvatarMetadata
|
||||
|
||||
+ (NSString *)collection
|
||||
{
|
||||
return @"AvatarMetadata";
|
||||
}
|
||||
|
||||
- (instancetype)initWithFileName:(NSString *)fileName
|
||||
avatarUrl:(NSString *)avatarUrl
|
||||
avatarDigest:(NSString *)avatarDigest
|
||||
{
|
||||
// TODO: Local filenames for avatars are guaranteed to be unique.
|
||||
self = [super initWithUniqueId:fileName];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
OWSAssert(fileName.length > 0);
|
||||
OWSAssert(avatarUrl.length > 0);
|
||||
OWSAssert(avatarDigest.length > 0);
|
||||
_fileName = fileName;
|
||||
_avatarUrl = avatarUrl;
|
||||
_avatarDigest = avatarDigest;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - NSObject
|
||||
|
||||
- (BOOL)isEqual:(AvatarMetadata *)other
|
||||
{
|
||||
return ([other isKindOfClass:[AvatarMetadata class]] && [self.fileName isEqualToString:other.fileName] &&
|
||||
[self.avatarUrl isEqualToString:other.avatarUrl] && [self.avatarDigest isEqualToString:other.avatarDigest]);
|
||||
}
|
||||
|
||||
- (NSUInteger)hash
|
||||
{
|
||||
return self.fileName.hash ^ self.avatarUrl.hash ^ self.avatarDigest.hash;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
NSString *const kNSNotificationName_LocalProfileDidChange = @"kNSNotificationName_LocalProfileDidChange";
|
||||
|
||||
NSString *const kOWSProfilesManager_Collection = @"kOWSProfilesManager_Collection";
|
||||
// This key is used to persist the local user's profile key.
|
||||
NSString *const kOWSProfilesManager_LocalProfileKey = @"kOWSProfilesManager_LocalProfileKey";
|
||||
NSString *const kOWSProfilesManager_LocalProfileSecretKey = @"kOWSProfilesManager_LocalProfileSecretKey";
|
||||
NSString *const kOWSProfilesManager_LocalProfileNameKey = @"kOWSProfilesManager_LocalProfileNameKey";
|
||||
NSString *const kOWSProfilesManager_LocalProfileAvatarMetadataKey
|
||||
= @"kOWSProfilesManager_LocalProfileAvatarMetadataKey";
|
||||
|
||||
// TODO:
|
||||
static const NSInteger kProfileKeyLength = 16;
|
||||
@ -22,7 +90,13 @@ static const NSInteger kProfileKeyLength = 16;
|
||||
@property (nonatomic, readonly) TSStorageManager *storageManager;
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
|
||||
@property (nonatomic, readonly, nullable) NSData *localProfileKey;
|
||||
@property (atomic, readonly, nullable) NSData *localProfileKey;
|
||||
|
||||
// These properties should only be mutated on the main thread,
|
||||
// but they may be accessed on other threads.
|
||||
@property (atomic, nullable) NSString *localProfileName;
|
||||
@property (atomic, nullable) UIImage *localProfileAvatarImage;
|
||||
@property (atomic, nullable) AvatarMetadata *localProfileAvatarMetadata;
|
||||
|
||||
@end
|
||||
|
||||
@ -72,18 +146,20 @@ static const NSInteger kProfileKeyLength = 16;
|
||||
[messageSender setProfilesManager:self];
|
||||
|
||||
// Try to load.
|
||||
_localProfileKey = [self.storageManager objectForKey:kOWSProfilesManager_LocalProfileKey
|
||||
_localProfileKey = [self.storageManager objectForKey:kOWSProfilesManager_LocalProfileSecretKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
if (!_localProfileKey) {
|
||||
// Generate
|
||||
_localProfileKey = [OWSProfilesManager generateLocalProfileKey];
|
||||
// Persist
|
||||
[self.storageManager setObject:_localProfileKey
|
||||
forKey:kOWSProfilesManager_LocalProfileKey
|
||||
forKey:kOWSProfilesManager_LocalProfileSecretKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
}
|
||||
OWSAssert(_localProfileKey.length == kProfileKeyLength);
|
||||
|
||||
[self loadLocalProfileAsync];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -100,19 +176,271 @@ static const NSInteger kProfileKeyLength = 16;
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void)appLaunchDidBegin
|
||||
{
|
||||
// Do nothing; we only want to make sure this singleton is created on startup.
|
||||
}
|
||||
|
||||
#pragma mark - Local Profile Key
|
||||
|
||||
+ (NSData *)generateLocalProfileKey
|
||||
{
|
||||
// TODO:
|
||||
OWSFail(@"Profile key generation is not yet implemented.");
|
||||
DDLogVerbose(@"%@ Profile key generation is not yet implemented.", self.tag);
|
||||
return [SecurityUtils generateRandomBytes:kProfileKeyLength];
|
||||
}
|
||||
|
||||
- (nullable NSData *)localProfileKey
|
||||
#pragma mark - Local Profile
|
||||
|
||||
// This method is use to update client "local profile" state.
|
||||
- (void)updateLocalProfileName:(nullable NSString *)localProfileName
|
||||
localProfileAvatarImage:(nullable UIImage *)localProfileAvatarImage
|
||||
localProfileAvatarMetadata:(nullable AvatarMetadata *)localProfileAvatarMetadata
|
||||
{
|
||||
OWSAssert(_localProfileKey.length == kProfileKeyLength);
|
||||
return _localProfileKey;
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
|
||||
// The avatar image and filename should both be set, or neither should be set.
|
||||
if (!localProfileAvatarMetadata && localProfileAvatarImage) {
|
||||
OWSFail(@"Missing avatar metadata.");
|
||||
localProfileAvatarImage = nil;
|
||||
}
|
||||
if (localProfileAvatarMetadata && !localProfileAvatarImage) {
|
||||
OWSFail(@"Missing avatar image.");
|
||||
localProfileAvatarMetadata = nil;
|
||||
}
|
||||
|
||||
self.localProfileName = localProfileName;
|
||||
self.localProfileAvatarImage = localProfileAvatarImage;
|
||||
self.localProfileAvatarMetadata = localProfileAvatarMetadata;
|
||||
|
||||
if (localProfileName) {
|
||||
[self.storageManager setObject:localProfileName
|
||||
forKey:kOWSProfilesManager_LocalProfileNameKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
} else {
|
||||
[self.storageManager removeObjectForKey:kOWSProfilesManager_LocalProfileNameKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
}
|
||||
if (localProfileAvatarMetadata) {
|
||||
[self.storageManager setObject:localProfileAvatarMetadata
|
||||
forKey:kOWSProfilesManager_LocalProfileAvatarMetadataKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
} else {
|
||||
[self.storageManager removeObjectForKey:kOWSProfilesManager_LocalProfileAvatarMetadataKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_LocalProfileDidChange
|
||||
object:nil
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
- (void)updateLocalProfileName:(nullable NSString *)localProfileName
|
||||
localProfileAvatarImage:(nullable UIImage *)localProfileAvatarImage
|
||||
success:(void (^)())successBlock
|
||||
failure:(void (^)())failureBlockParameter
|
||||
{
|
||||
OWSAssert([NSThread isMainThread]);
|
||||
OWSAssert(successBlock);
|
||||
OWSAssert(failureBlockParameter);
|
||||
|
||||
// Ensure that the failure block is called on the main thread.
|
||||
void (^failureBlock)() = ^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
failureBlockParameter();
|
||||
});
|
||||
};
|
||||
|
||||
// The final steps are to:
|
||||
//
|
||||
// * Try to update the service.
|
||||
// * Update client state on success.
|
||||
void (^tryToUpdateService)(AvatarMetadata *_Nullable) = ^(AvatarMetadata *_Nullable avatarMetadata) {
|
||||
[self updateProfileOnService:localProfileName
|
||||
avatarMetadata:avatarMetadata
|
||||
success:^{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateLocalProfileName:localProfileName
|
||||
localProfileAvatarImage:localProfileAvatarImage
|
||||
localProfileAvatarMetadata:avatarMetadata];
|
||||
successBlock();
|
||||
});
|
||||
}
|
||||
failure:^{
|
||||
failureBlock();
|
||||
}];
|
||||
};
|
||||
|
||||
// If we have a new avatar image, we must first:
|
||||
//
|
||||
// * Encode it to JPEG.
|
||||
// * Write it to disk.
|
||||
// * Upload it to service.
|
||||
if (localProfileAvatarImage) {
|
||||
if (self.localProfileAvatarMetadata && self.localProfileAvatarImage == localProfileAvatarImage) {
|
||||
DDLogVerbose(@"%@ Updating local profile on service with unchanged avatar.", self.tag);
|
||||
// If the avatar hasn't changed, reuse the existing metadata.
|
||||
tryToUpdateService(self.localProfileAvatarMetadata);
|
||||
} else {
|
||||
DDLogVerbose(@"%@ Updating local profile on service with new avatar.", self.tag);
|
||||
[self writeAvatarToDisk:localProfileAvatarImage
|
||||
success:^(NSData *data, NSString *fileName) {
|
||||
[self uploadAvatarToService:data
|
||||
fileName:fileName
|
||||
success:^(AvatarMetadata *avatarMetadata) {
|
||||
tryToUpdateService(avatarMetadata);
|
||||
}
|
||||
failure:^{
|
||||
failureBlock();
|
||||
}];
|
||||
}
|
||||
failure:^{
|
||||
failureBlock();
|
||||
}];
|
||||
}
|
||||
} else {
|
||||
DDLogVerbose(@"%@ Updating local profile on service with no avatar.", self.tag);
|
||||
tryToUpdateService(nil);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)writeAvatarToDisk:(UIImage *)avatar
|
||||
success:(void (^)(NSData *data, NSString *fileName))successBlock
|
||||
failure:(void (^)())failureBlock
|
||||
{
|
||||
OWSAssert(avatar);
|
||||
OWSAssert(successBlock);
|
||||
OWSAssert(failureBlock);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (avatar) {
|
||||
NSData *_Nullable data = UIImageJPEGRepresentation(avatar, 1.f);
|
||||
OWSAssert(data);
|
||||
if (data) {
|
||||
NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingPathExtension:@"jpg"];
|
||||
NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:fileName];
|
||||
BOOL success = [data writeToFile:filePath atomically:YES];
|
||||
OWSAssert(success);
|
||||
if (success) {
|
||||
successBlock(data, fileName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
failureBlock();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: The exact API & encryption scheme for avatars is not yet settled.
|
||||
- (void)uploadAvatarToService:(NSData *)data
|
||||
fileName:(NSString *)fileName
|
||||
success:(void (^)(AvatarMetadata *avatarMetadata))successBlock
|
||||
failure:(void (^)())failureBlock
|
||||
{
|
||||
OWSAssert(data.length > 0);
|
||||
OWSAssert(fileName.length > 0);
|
||||
OWSAssert(successBlock);
|
||||
OWSAssert(failureBlock);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
// TODO:
|
||||
NSString *avatarUrl = @"avatarUrl";
|
||||
NSString *avatarDigest = @"digest";
|
||||
AvatarMetadata *avatarMetadata =
|
||||
[[AvatarMetadata alloc] initWithFileName:fileName avatarUrl:avatarUrl avatarDigest:avatarDigest];
|
||||
if (YES) {
|
||||
successBlock(avatarMetadata);
|
||||
return;
|
||||
}
|
||||
failureBlock();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: The exact API & encryption scheme for profiles is not yet settled.
|
||||
- (void)updateProfileOnService:(nullable NSString *)localProfileName
|
||||
avatarMetadata:(nullable AvatarMetadata *)avatarMetadata
|
||||
success:(void (^)())successBlock
|
||||
failure:(void (^)())failureBlock
|
||||
{
|
||||
OWSAssert(successBlock);
|
||||
OWSAssert(failureBlock);
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
// TODO:
|
||||
if (YES) {
|
||||
successBlock();
|
||||
return;
|
||||
}
|
||||
failureBlock();
|
||||
});
|
||||
}
|
||||
|
||||
- (void)loadLocalProfileAsync
|
||||
{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
NSString *_Nullable localProfileName = [self.storageManager objectForKey:kOWSProfilesManager_LocalProfileNameKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
AvatarMetadata *_Nullable localProfileAvatarMetadata =
|
||||
[self.storageManager objectForKey:kOWSProfilesManager_LocalProfileAvatarMetadataKey
|
||||
inCollection:kOWSProfilesManager_Collection];
|
||||
UIImage *_Nullable localProfileAvatarImage = nil;
|
||||
if (localProfileAvatarMetadata) {
|
||||
localProfileAvatarImage = [self loadProfileAvatarWithFilename:localProfileAvatarMetadata.fileName];
|
||||
if (!localProfileAvatarImage) {
|
||||
localProfileAvatarMetadata = nil;
|
||||
}
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.localProfileName = localProfileName;
|
||||
self.localProfileAvatarImage = localProfileAvatarImage;
|
||||
self.localProfileAvatarMetadata = localProfileAvatarMetadata;
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:kNSNotificationName_LocalProfileDidChange
|
||||
object:nil
|
||||
userInfo:nil];
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark - Avatar Disk Cache
|
||||
|
||||
- (nullable UIImage *)loadProfileAvatarWithFilename:(NSString *)fileName
|
||||
{
|
||||
OWSAssert(fileName.length > 0);
|
||||
|
||||
NSString *filePath = [self.profileAvatarsDirPath stringByAppendingPathComponent:fileName];
|
||||
UIImage *_Nullable image = [UIImage imageWithContentsOfFile:filePath];
|
||||
return image;
|
||||
}
|
||||
|
||||
- (NSString *)profileAvatarsDirPath
|
||||
{
|
||||
static NSString *profileAvatarsDirPath = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSString *documentsPath =
|
||||
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
|
||||
profileAvatarsDirPath = [documentsPath stringByAppendingPathComponent:@"ProfileAvatars"];
|
||||
|
||||
BOOL isDirectory;
|
||||
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:profileAvatarsDirPath isDirectory:&isDirectory];
|
||||
if (exists) {
|
||||
OWSAssert(isDirectory);
|
||||
|
||||
DDLogInfo(@"Profile avatars directory already exists");
|
||||
} else {
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] createDirectoryAtPath:profileAvatarsDirPath
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (error) {
|
||||
DDLogError(@"Failed to create profile avatars directory: %@", error);
|
||||
}
|
||||
}
|
||||
});
|
||||
return profileAvatarsDirPath;
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
@ -277,7 +277,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
#if TARGET_OS_IPHONE
|
||||
NSURL *fileURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
|
||||
NSString *path = [fileURL path];
|
||||
databasePath = [path stringByAppendingFormat:@"/%@", databaseName];
|
||||
databasePath = [path stringByAppendingPathComponent:databaseName];
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier];
|
||||
@ -289,7 +289,7 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
|
||||
[fileManager createDirectoryAtURL:appDirectory withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
}
|
||||
|
||||
databasePath = [appDirectory.filePathURL.absoluteString stringByAppendingFormat:@"/%@", databaseName];
|
||||
databasePath = [appDirectory.filePathURL.absoluteString stringByAppendingPathComponent:databaseName];
|
||||
#endif
|
||||
|
||||
return databasePath;
|
||||
|
||||
@ -364,36 +364,41 @@ NSString *const OWSMimeTypeUnknownForTests = @"unknown/mimetype";
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForImage:(NSString *)uniqueId ofMIMEType:(NSString *)contentType inFolder:(NSString *)folder {
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId]
|
||||
stringByAppendingPathExtension:[self getSupportedExtensionFromImageMIMEType:contentType]];
|
||||
return [self filePathForData:uniqueId
|
||||
withFileExtension:[self getSupportedExtensionFromImageMIMEType:contentType]
|
||||
inFolder:folder];
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForVideo:(NSString *)uniqueId ofMIMEType:(NSString *)contentType inFolder:(NSString *)folder {
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId]
|
||||
stringByAppendingPathExtension:[self getSupportedExtensionFromVideoMIMEType:contentType]];
|
||||
return [self filePathForData:uniqueId
|
||||
withFileExtension:[self getSupportedExtensionFromVideoMIMEType:contentType]
|
||||
inFolder:folder];
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForAudio:(NSString *)uniqueId ofMIMEType:(NSString *)contentType inFolder:(NSString *)folder {
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId]
|
||||
stringByAppendingPathExtension:[self getSupportedExtensionFromAudioMIMEType:contentType]];
|
||||
return [self filePathForData:uniqueId
|
||||
withFileExtension:[self getSupportedExtensionFromAudioMIMEType:contentType]
|
||||
inFolder:folder];
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForAnimated:(NSString *)uniqueId ofMIMEType:(NSString *)contentType inFolder:(NSString *)folder {
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId]
|
||||
stringByAppendingPathExtension:[self getSupportedExtensionFromAnimatedMIMEType:contentType]];
|
||||
return [self filePathForData:uniqueId
|
||||
withFileExtension:[self getSupportedExtensionFromAnimatedMIMEType:contentType]
|
||||
inFolder:folder];
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForBinaryData:(NSString *)uniqueId ofMIMEType:(NSString *)contentType inFolder:(NSString *)folder
|
||||
{
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId]
|
||||
stringByAppendingPathExtension:[self getSupportedExtensionFromBinaryDataMIMEType:contentType]];
|
||||
return [self filePathForData:uniqueId
|
||||
withFileExtension:[self getSupportedExtensionFromBinaryDataMIMEType:contentType]
|
||||
inFolder:folder];
|
||||
}
|
||||
|
||||
+ (NSString *)filePathForData:(NSString *)uniqueId
|
||||
withFileExtension:(NSString *)fileExtension
|
||||
inFolder:(NSString *)folder
|
||||
{
|
||||
return [[folder stringByAppendingFormat:@"/%@", uniqueId] stringByAppendingPathExtension:fileExtension];
|
||||
return [folder stringByAppendingPathComponent:[uniqueId stringByAppendingPathExtension:fileExtension]];
|
||||
}
|
||||
|
||||
+ (nullable NSString *)utiTypeForMIMEType:(NSString *)mimeType
|
||||
|
||||
Loading…
Reference in New Issue
Block a user