1
0
mirror of https://github.com/danog/Telegram.git synced 2024-12-04 02:17:51 +01:00
Telegram/Watch/Extension/TGUserInfoController.m
2016-02-25 01:03:51 +01:00

507 lines
15 KiB
Objective-C

#import "TGUserInfoController.h"
#import "TGStringUtils.h"
#import "TGBridgeBotSignals.h"
#import "TGBridgeUserInfoSignals.h"
#import "TGBridgePeerSettingsSignals.h"
#import "TGBridgeUser.h"
#import "TGBridgeBotInfo.h"
#import "TGBridgeUserCache.h"
#import "TGUserHandle.h"
#import "TGBridgeChat.h"
#import "TGTableDeltaUpdater.h"
#import "WKInterfaceTable+TGDataDrivenTable.h"
#import "TGInterfaceMenu.h"
#import "TGUserInfoHeaderController.h"
#import "TGUserHandleRowController.h"
#import "TGProfilePhotoController.h"
#import "TGNeoConversationController.h"
NSString *const TGUserInfoControllerIdentifier = @"TGUserInfoController";
@implementation TGUserInfoControllerContext
- (instancetype)initWithUser:(TGBridgeUser *)user
{
self = [super init];
if (self != nil)
{
_user = user;
}
return self;
}
- (instancetype)initWithUserId:(int32_t)userId
{
self = [super init];
if (self != nil)
{
_userId = userId;
}
return self;
}
- (instancetype)initWithChannel:(TGBridgeChat *)channel
{
self = [super init];
if (self != nil)
{
_channel = channel;
}
return self;
}
@end
@interface TGUserInfoController () <TGTableDataSource>
{
SMetaDisposable *_userDisposable;
SMetaDisposable *_botInfoDisposable;
SMetaDisposable *_peerSettingsDisposable;
SMetaDisposable *_updateSettingsDisposable;
TGUserInfoControllerContext *_context;
TGBridgeUser *_userModel;
TGBridgeBotInfo *_botInfo;
bool _muted;
bool _blocked;
TGBridgeChat *_channelModel;
NSArray *_handleModels;
NSArray *_currentHandleModels;
TGInterfaceMenu *_menu;
}
@end
@implementation TGUserInfoController
- (instancetype)init
{
self = [super init];
if (self != nil)
{
_userDisposable = [[SMetaDisposable alloc] init];
_peerSettingsDisposable = [[SMetaDisposable alloc] init];
_updateSettingsDisposable = [[SMetaDisposable alloc] init];
[self.table _setInitialHidden:true];
self.table.tableDataSource = self;
}
return self;
}
- (void)dealloc
{
[_userDisposable dispose];
[_botInfoDisposable dispose];
[_peerSettingsDisposable dispose];
[_updateSettingsDisposable dispose];
}
- (void)configureWithContext:(TGUserInfoControllerContext *)context
{
_context = context;
if (context.channel != nil)
[self configureWithChannelContext:context];
else
[self configureWithUserContext:context];
}
- (void)configureWithChannelContext:(TGUserInfoControllerContext *)context
{
_channelModel = context.channel;
self.title = _channelModel.isChannelGroup ? TGLocalized(@"Watch.GroupInfo.Title") : TGLocalized(@"Watch.ChannelInfo.Title");
[self updateChannelHandles];
__weak TGUserInfoController *weakSelf = self;
[self performInterfaceUpdate:^(bool animated)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf reloadData];
}];
[self setupPeerSettingsWithId:_channelModel.identifier];
}
- (void)configureWithUserContext:(TGUserInfoControllerContext *)context
{
self.title = TGLocalized(@"Watch.UserInfo.Title");
int32_t userId = (_context.user != nil) ? _context.user.identifier : _context.userId;
SSignal *remoteUserSignal = [TGBridgeUserInfoSignals userInfoWithUserId:userId];
SSignal *userSignal = nil;
TGBridgeUser *cachedUser = [[TGBridgeUserCache instance] userWithId:userId];
if (cachedUser == nil)
cachedUser = _context.user;
if (cachedUser != nil)
userSignal = [[SSignal single:cachedUser] then:remoteUserSignal];
else
userSignal = remoteUserSignal;
__weak TGUserInfoController *weakSelf = self;
[_userDisposable setDisposable:[[userSignal deliverOn:[SQueue mainQueue]] startWithNext:^(TGBridgeUser *user)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_userModel = user;
[[TGBridgeUserCache instance] storeUser:user];
if ([strongSelf _userIsBot] && (strongSelf->_botInfo == nil || user.botVersion > strongSelf->_botInfo.version))
{
strongSelf->_botInfoDisposable = [[SMetaDisposable alloc] init];
[strongSelf->_botInfoDisposable setDisposable:[[TGBridgeBotSignals botInfoForUserId:user.identifier] startWithNext:^(TGBridgeBotInfo *botInfo)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_botInfo = botInfo;
[strongSelf updateUserHandles];
[strongSelf performInterfaceUpdate:^(bool animated)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf reloadData];
}];
}]];
}
[strongSelf updateUserHandles];
[strongSelf performInterfaceUpdate:^(bool animated)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf reloadData];
}];
}]];
[self setupPeerSettingsWithId:userId];
}
- (void)setupPeerSettingsWithId:(int64_t)peerId
{
__weak TGUserInfoController *weakSelf = self;
[_peerSettingsDisposable setDisposable:[[TGBridgePeerSettingsSignals peerSettingsWithPeerId:peerId] startWithNext:^(NSDictionary *next)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
TGBridgePeerNotificationSettings *settings = next[@"notifications"];
bool blocked = [next[@"blocked"] boolValue];
bool muted = (settings.muteFor > 0);
strongSelf->_blocked = blocked;
strongSelf->_muted = muted;
[strongSelf performInterfaceUpdate:^(bool animated)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf reloadData];
}];
}]];
}
- (void)updateUserHandles
{
NSMutableArray *handles = [[NSMutableArray alloc] init];
if ([self _userHasPhone])
{
[handles addObject:[[TGUserHandle alloc] initWithHandle:_userModel.prettyPhoneNumber type:TGLocalized(@"UserInfo.GenericPhoneLabel") handleType:TGUserHandleTypePhone data:_userModel.phoneNumber]];
}
if ([self _userHasUsername])
{
[handles addObject:[[TGUserHandle alloc] initWithHandle:[NSString stringWithFormat:@"@%@", self->_userModel.userName] type:TGLocalized(@"Profile.Username") handleType:TGUserHandleTypeUndefined data:nil]];
}
if ([self _botHasDescription])
{
[handles addObject:[[TGUserHandle alloc] initWithHandle:_botInfo.shortDescription type:TGLocalized(@"Profile.BotInfo") handleType:TGUserHandleTypeDescription data:nil]];
}
_handleModels = handles;
}
- (void)updateChannelHandles
{
NSMutableArray *handles = [[NSMutableArray alloc] init];
if (_channelModel.userName.length > 0)
{
[handles addObject:[[TGUserHandle alloc] initWithHandle:[NSString stringWithFormat:@"telegram.me/%@", self->_channelModel.userName] type:TGLocalized(@"Channel.LinkItem") handleType:TGUserHandleTypeUndefined data:nil]];
}
if (_channelModel.about.length > 0)
{
[handles addObject:[[TGUserHandle alloc] initWithHandle:_channelModel.about type:TGLocalized(@"Channel.AboutItem") handleType:TGUserHandleTypeDescription data:nil]];
}
_handleModels = handles;
}
- (void)reloadData
{
NSArray *currentHandles = _currentHandleModels;
_currentHandleModels = _handleModels;
self.activityIndicator.hidden = true;
NSInteger numberOfRows = [self numberOfRowsInTable:self.table section:0];
if (self.table.numberOfRows == numberOfRows + 1)
{
[self.table reloadHeader];
NSMutableArray *indexPaths = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < numberOfRows; i++)
[indexPaths addObject:[TGIndexPath indexPathForRow:i inSection:0]];
[self.table reloadRowsAtIndexPaths:indexPaths];
}
else
{
if (self.table.hidden)
{
[self.table reloadData];
}
else
{
[TGTableDeltaUpdater updateTable:self.table oldData:currentHandles newData:_currentHandleModels controllerClassForIndexPath:^Class(TGIndexPath *indexPath)
{
return nil;
}];
}
}
[self updateMenuItems];
self.table.hidden = false;
}
- (void)willActivate
{
[super willActivate];
[self.table notifyVisiblityChange];
}
- (void)didDeactivate
{
[super didDeactivate];
}
#pragma mark -
- (void)updateMenuItems
{
[_menu clearItems];
if (_menu == nil)
_menu = [[TGInterfaceMenu alloc] initForInterfaceController:self];
__weak TGUserInfoController *weakSelf = self;
NSMutableArray *menuItems = [[NSMutableArray alloc] init];
bool muted = _muted;
bool blocked = _blocked;
bool muteForever = _channelModel.isChannelGroup;
int32_t muteFor = muteForever ? INT_MAX : 1;
NSString *muteTitle = muteForever ? TGLocalized(@"Watch.UserInfo.Mute") : [NSString stringWithFormat:TGLocalized([TGStringUtils integerValueFormat:@"Watch.UserInfo.Mute_" value:muteFor]), muteFor];
TGInterfaceMenuItem *muteItem = [[TGInterfaceMenuItem alloc] initWithItemIcon:muted ? WKMenuItemIconSpeaker : WKMenuItemIconMute title:muted ? TGLocalized(@"Watch.UserInfo.Unmute") : muteTitle actionBlock:^(TGInterfaceController *controller, TGInterfaceMenuItem *sender)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
TGBridgePeerNotificationSettings *settings = [[TGBridgePeerNotificationSettings alloc] init];
settings.muteFor = muted ? 0 : (muteFor == INT_MAX ? INT_MAX : muteFor * 60 * 60);
[strongSelf->_updateSettingsDisposable setDisposable:[[TGBridgePeerSettingsSignals updateNotificationSettingsWithPeerId:strongSelf->_userModel.identifier settings:settings] startWithNext:nil completed:^
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_muted = !muted;
[strongSelf updateMenuItems];
}]];
}];
[menuItems addObject:muteItem];
if (_channelModel == nil)
{
TGInterfaceMenuItem *blockItem = [[TGInterfaceMenuItem alloc] initWithItemIcon:WKMenuItemIconBlock title:blocked ? TGLocalized(@"Watch.UserInfo.Unblock") : TGLocalized(@"Watch.UserInfo.Block") actionBlock:^(TGInterfaceController *controller, TGInterfaceMenuItem *sender)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
[strongSelf->_updateSettingsDisposable setDisposable:[[TGBridgePeerSettingsSignals updateBlockStatusWithPeerId:strongSelf->_userModel.identifier blocked:!blocked] startWithNext:nil completed:^
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
strongSelf->_blocked = !blocked;
[strongSelf updateMenuItems];
}]];
}];
[menuItems addObject:blockItem];
}
if (!_context.disallowCompose)
{
TGInterfaceMenuItem *composeItem = [[TGInterfaceMenuItem alloc] initWithImageNamed:@"Compose" title:TGLocalized(@"Watch.UserInfo.SendMessage") actionBlock:^(TGInterfaceController *controller, TGInterfaceMenuItem *sender)
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
TGNeoConversationControllerContext *context = [[TGNeoConversationControllerContext alloc] initWithPeerId:strongSelf->_userModel.identifier];
[strongSelf pushControllerWithClass:[TGNeoConversationController class] context:context];
}];
[menuItems addObject:composeItem];
}
[_menu addItems:menuItems];
}
#pragma mark -
- (Class)headerControllerClassForTable:(WKInterfaceTable *)table
{
return [TGUserInfoHeaderController class];
}
- (void)table:(WKInterfaceTable *)table updateHeaderController:(TGUserInfoHeaderController *)controller
{
__weak TGUserInfoController *weakSelf = self;
controller.isVisible = ^bool
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return false;
return strongSelf.isVisible;
};
controller.avatarPressed = ^
{
__strong TGUserInfoController *strongSelf = weakSelf;
if (strongSelf == nil)
return;
NSString *url = nil;
if (strongSelf->_userModel != nil)
url = strongSelf->_userModel.photoSmall;
else if (strongSelf->_channelModel != nil)
url = strongSelf->_channelModel.groupPhotoSmall;
if (url != nil)
{
TGProfilePhotoControllerContext *context = [[TGProfilePhotoControllerContext alloc] initWithImageUrl:url];
[strongSelf pushControllerWithClass:[TGProfilePhotoController class] context:context];
}
};
if (_userModel != nil)
[controller updateWithUser:_userModel context:_context.context];
else
[controller updateWithChannel:_channelModel];
}
- (NSUInteger)numberOfRowsInTable:(WKInterfaceTable *)table section:(NSUInteger)section
{
return _currentHandleModels.count;
}
- (Class)table:(WKInterfaceTable *)table rowControllerClassAtIndexPath:(TGIndexPath *)indexPath
{
TGUserHandle *userHandle = _currentHandleModels[indexPath.row];
switch (userHandle.handleType)
{
case TGUserHandleTypePhone:
return [TGUserHandleActiveRowController class];
break;
default:
return [TGUserHandleRowController class];
}
}
- (void)table:(WKInterfaceTable *)table updateRowController:(TGUserHandleRowController *)controller forIndexPath:(TGIndexPath *)indexPath
{
TGUserHandle *userHandle = _currentHandleModels[indexPath.row];
[controller updateWithUserHandle:userHandle];
}
- (void)table:(WKInterfaceTable *)table didSelectRowAtIndexPath:(TGIndexPath *)indexPath
{
TGUserHandle *userHandle = _currentHandleModels[indexPath.row];
switch (userHandle.handleType)
{
case TGUserHandleTypePhone:
[[WKExtension sharedExtension] openSystemURL:[NSURL URLWithString:[NSString stringWithFormat:@"tel://%@", userHandle.data]]];
break;
default:
break;
}
}
- (bool)_userHasPhone
{
return (_userModel.phoneNumber.length > 0);
}
- (bool)_userHasUsername
{
return (_userModel.userName.length > 0);
}
- (bool)_userIsBot
{
return (_userModel.kind != TGBridgeUserKindGeneric);
}
- (bool)_botHasDescription
{
return (_botInfo.shortDescription.length > 0);
}
#pragma mark -
+ (NSString *)identifier
{
return TGUserInfoControllerIdentifier;
}
@end