684 lines
25 KiB
Objective-C
684 lines
25 KiB
Objective-C
/*
|
|
Copyright 2018-2024 New Vector Ltd.
|
|
Copyright 2017 Vector Creations Ltd
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
Please see LICENSE in the repository root for full details.
|
|
*/
|
|
|
|
#import "WidgetViewController.h"
|
|
|
|
#import "IntegrationManagerViewController.h"
|
|
#import "GeneratedInterface-Swift.h"
|
|
|
|
NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse('%@', %@);";
|
|
|
|
@interface WidgetViewController () <ServiceTermsModalCoordinatorBridgePresenterDelegate>
|
|
|
|
@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;
|
|
@property (nonatomic, strong) NSString *widgetUrl;
|
|
|
|
@property (nonatomic, strong) SlidingModalPresenter *slidingModalPresenter;
|
|
|
|
@end
|
|
|
|
@implementation WidgetViewController
|
|
@synthesize widget;
|
|
|
|
- (instancetype)initWithUrl:(NSString*)widgetUrl forWidget:(Widget*)theWidget
|
|
{
|
|
// The opening of the url is delayed in viewWillAppear where we will check
|
|
// the widget permission
|
|
self = [super initWithURL:nil];
|
|
if (self)
|
|
{
|
|
self.widgetUrl = widgetUrl;
|
|
widget = theWidget;
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
webView.scrollView.bounces = NO;
|
|
|
|
// Disable opacity so that the webview background uses the current interface theme
|
|
webView.opaque = NO;
|
|
|
|
if (widget)
|
|
{
|
|
self.navigationItem.title = widget.name ? widget.name : widget.type;
|
|
|
|
UIBarButtonItem *menuButton = [[UIBarButtonItem alloc] initWithImage:AssetImages.roomContextMenuMore.image style:UIBarButtonItemStylePlain target:self action:@selector(onMenuButtonPressed:)];
|
|
self.navigationItem.rightBarButtonItem = menuButton;
|
|
}
|
|
|
|
self.slidingModalPresenter = [SlidingModalPresenter new];
|
|
}
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
|
|
// Check widget permission before opening the widget
|
|
[self checkWidgetPermissionWithCompletion:^(BOOL granted) {
|
|
|
|
[self.slidingModalPresenter dismissWithAnimated:YES completion:nil];
|
|
|
|
if (granted)
|
|
{
|
|
self.URL = self.widgetUrl;
|
|
}
|
|
else
|
|
{
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)reloadWidget
|
|
{
|
|
self.URL = self.widgetUrl;
|
|
}
|
|
|
|
- (BOOL)hasUserEnoughPowerToManageCurrentWidget
|
|
{
|
|
BOOL hasUserEnoughPower = NO;
|
|
|
|
MXSession *session = widget.mxSession;
|
|
MXRoom *room = [session roomWithRoomId:self.widget.roomId];
|
|
MXRoomState *roomState = room.dangerousSyncState;
|
|
if (roomState)
|
|
{
|
|
// Check user's power in the room
|
|
MXRoomPowerLevels *powerLevels = roomState.powerLevels;
|
|
NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:session.myUser.userId];
|
|
|
|
// The user must be able to send state events to manage widgets
|
|
if (oneSelfPowerLevel >= powerLevels.stateDefault)
|
|
{
|
|
hasUserEnoughPower = YES;
|
|
}
|
|
}
|
|
|
|
return hasUserEnoughPower;
|
|
}
|
|
|
|
- (void)removeCurrentWidget
|
|
{
|
|
WidgetManager *widgetManager = [WidgetManager sharedManager];
|
|
|
|
MXRoom *room = [self.widget.mxSession roomWithRoomId:self.widget.roomId];
|
|
NSString *widgetId = self.widget.widgetId;
|
|
if (room && widgetId)
|
|
{
|
|
[widgetManager closeWidget:widgetId inRoom:room success:^{
|
|
} failure:^(NSError *error) {
|
|
MXLogDebug(@"[WidgetVC] removeCurrentWidget failed. Error: %@", error);
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)showErrorAsAlert:(NSError*)error
|
|
{
|
|
NSString *title = [error.userInfo valueForKey:NSLocalizedFailureReasonErrorKey];
|
|
NSString *msg = [error.userInfo valueForKey:NSLocalizedDescriptionKey];
|
|
if (!title)
|
|
{
|
|
if (msg)
|
|
{
|
|
title = msg;
|
|
msg = nil;
|
|
}
|
|
else
|
|
{
|
|
title = [VectorL10n error];
|
|
}
|
|
}
|
|
|
|
__weak __typeof__(self) weakSelf = self;
|
|
|
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
|
|
[alert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action) {
|
|
|
|
typeof(self) self = weakSelf;
|
|
|
|
if (self)
|
|
{
|
|
// Leave this widget VC
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}
|
|
|
|
}]];
|
|
|
|
[self presentViewController:alert animated:YES completion:nil];
|
|
}
|
|
|
|
|
|
#pragma mark - Widget Permission
|
|
|
|
- (void)checkWidgetPermissionWithCompletion:(void (^)(BOOL granted))completion
|
|
{
|
|
MXSession *session = widget.mxSession;
|
|
|
|
if ([widget.widgetEvent.sender isEqualToString:session.myUser.userId])
|
|
{
|
|
// No need of more permission check if the user created the widget
|
|
completion(YES);
|
|
return;
|
|
}
|
|
|
|
// Check permission in user Riot settings
|
|
__block RiotSharedSettings *sharedSettings = [[RiotSharedSettings alloc] initWithSession:session];
|
|
|
|
WidgetPermission permission = [sharedSettings permissionFor:widget];
|
|
if (permission == WidgetPermissionGranted)
|
|
{
|
|
completion(YES);
|
|
}
|
|
else
|
|
{
|
|
// Note: ask permission again if the user previously declined it
|
|
[self askPermissionWithCompletion:^(BOOL granted) {
|
|
// Update the settings in user account data in parallel
|
|
[sharedSettings setPermission:granted ? WidgetPermissionGranted : WidgetPermissionDeclined
|
|
for:self.widget
|
|
success:^
|
|
{
|
|
sharedSettings = nil;
|
|
}
|
|
failure:^(NSError * _Nullable error)
|
|
{
|
|
MXLogDebug(@"[WidgetVC] setPermissionForWidget failed. Error: %@", error);
|
|
sharedSettings = nil;
|
|
}];
|
|
|
|
completion(granted);
|
|
}];
|
|
}
|
|
}
|
|
|
|
- (void)askPermissionWithCompletion:(void (^)(BOOL granted))completion
|
|
{
|
|
NSString *widgetCreatorUserId = self.widget.widgetEvent.sender ?: [VectorL10n roomParticipantsUnknown];
|
|
|
|
MXSession *session = widget.mxSession;
|
|
MXRoom *room = [session roomWithRoomId:self.widget.widgetEvent.roomId];
|
|
MXRoomState *roomState = room.dangerousSyncState;
|
|
MXRoomMember *widgetCreatorRoomMember = [roomState.members memberWithUserId:widgetCreatorUserId];
|
|
|
|
NSString *widgetDomain = @"";
|
|
|
|
if (widget.url)
|
|
{
|
|
NSString *host = [[NSURL alloc] initWithString:widget.url].host;
|
|
if (host)
|
|
{
|
|
widgetDomain = host;
|
|
}
|
|
}
|
|
|
|
MXMediaManager *mediaManager = widget.mxSession.mediaManager;
|
|
NSString *widgetCreatorDisplayName = widgetCreatorRoomMember.displayname;
|
|
NSString *widgetCreatorAvatarURL = widgetCreatorRoomMember.avatarUrl;
|
|
|
|
NSArray<NSString*> *permissionStrings = @[
|
|
[VectorL10n roomWidgetPermissionDisplayNamePermission],
|
|
[VectorL10n roomWidgetPermissionAvatarUrlPermission],
|
|
[VectorL10n roomWidgetPermissionUserIdPermission],
|
|
[VectorL10n roomWidgetPermissionThemePermission],
|
|
[VectorL10n roomWidgetPermissionWidgetIdPermission],
|
|
[VectorL10n roomWidgetPermissionRoomIdPermission]
|
|
];
|
|
|
|
|
|
WidgetPermissionViewModel *widgetPermissionViewModel = [[WidgetPermissionViewModel alloc] initWithCreatorUserId:widgetCreatorUserId
|
|
creatorDisplayName:widgetCreatorDisplayName creatorAvatarUrl:widgetCreatorAvatarURL widgetDomain:widgetDomain
|
|
isWebviewWidget:YES
|
|
widgetPermissions:permissionStrings
|
|
mediaManager:mediaManager];
|
|
|
|
|
|
WidgetPermissionViewController *widgetPermissionViewController = [WidgetPermissionViewController instantiateWith:widgetPermissionViewModel];
|
|
|
|
widgetPermissionViewController.didTapContinueButton = ^{
|
|
completion(YES);
|
|
};
|
|
|
|
widgetPermissionViewController.didTapCloseButton = ^{
|
|
completion(NO);
|
|
};
|
|
|
|
|
|
[self.slidingModalPresenter present:widgetPermissionViewController from:self animated:YES completion:nil];
|
|
}
|
|
|
|
- (void)revokePermissionForCurrentWidget
|
|
{
|
|
MXSession *session = widget.mxSession;
|
|
__block RiotSharedSettings *sharedSettings = [[RiotSharedSettings alloc] initWithSession:session];
|
|
|
|
[sharedSettings setPermission:WidgetPermissionDeclined for:widget success:^{
|
|
sharedSettings = nil;
|
|
} failure:^(NSError * _Nullable error) {
|
|
MXLogDebug(@"[WidgetVC] revokePermissionForCurrentWidget failed. Error: %@", error);
|
|
sharedSettings = nil;
|
|
}];
|
|
}
|
|
|
|
|
|
#pragma mark - Contextual Menu
|
|
|
|
- (IBAction)onMenuButtonPressed:(id)sender
|
|
{
|
|
[self showMenu];
|
|
}
|
|
|
|
-(void)showMenu
|
|
{
|
|
MXSession *session = widget.mxSession;
|
|
|
|
UIAlertController *menu = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
|
|
|
[menu addAction:[UIAlertAction actionWithTitle:[VectorL10n widgetMenuRefresh]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action)
|
|
{
|
|
[self reloadWidget];
|
|
}]];
|
|
|
|
NSURL *url = [NSURL URLWithString:self.widgetUrl];
|
|
if (url && [[UIApplication sharedApplication] canOpenURL:url])
|
|
{
|
|
[menu addAction:[UIAlertAction actionWithTitle:[VectorL10n widgetMenuOpenOutside]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action)
|
|
{
|
|
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
|
|
}];
|
|
}]];
|
|
}
|
|
|
|
if (![widget.widgetEvent.sender isEqualToString:session.myUser.userId])
|
|
{
|
|
[menu addAction:[UIAlertAction actionWithTitle:[VectorL10n widgetMenuRevokePermission]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action)
|
|
{
|
|
[self revokePermissionForCurrentWidget];
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}]];
|
|
}
|
|
|
|
if ([self hasUserEnoughPowerToManageCurrentWidget])
|
|
{
|
|
[menu addAction:[UIAlertAction actionWithTitle:[VectorL10n widgetMenuRemove]
|
|
style:UIAlertActionStyleDefault
|
|
handler:^(UIAlertAction * action)
|
|
{
|
|
[self removeCurrentWidget];
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}]];
|
|
}
|
|
|
|
[menu addAction:[UIAlertAction actionWithTitle:[VectorL10n cancel]
|
|
style:UIAlertActionStyleCancel
|
|
handler:^(UIAlertAction * action) {
|
|
}]];
|
|
|
|
[self presentViewController:menu animated:YES completion:nil];
|
|
}
|
|
|
|
|
|
#pragma mark - WKNavigationDelegate
|
|
|
|
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
|
|
{
|
|
[self enableDebug];
|
|
|
|
// Setup js code
|
|
NSString *path = [[NSBundle mainBundle] pathForResource:@"postMessageAPI" ofType:@"js"];
|
|
NSString *js = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
|
[webView evaluateJavaScript:js completionHandler:nil];
|
|
|
|
[self stopActivityIndicator];
|
|
|
|
// Check connectivity
|
|
if ([AppDelegate theDelegate].isOffline)
|
|
{
|
|
// The web page may be in the cache, so its loading will be successful
|
|
// but we cannot go further, it often leads to a blank screen.
|
|
// So, display an error so that the user can escape.
|
|
NSError *error = [NSError errorWithDomain:NSURLErrorDomain
|
|
code:NSURLErrorNotConnectedToInternet
|
|
userInfo:@{
|
|
NSLocalizedDescriptionKey : [VectorL10n networkOfflinePrompt]
|
|
}];
|
|
[self showErrorAsAlert:error];
|
|
}
|
|
}
|
|
|
|
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
|
|
{
|
|
NSString *urlString = navigationAction.request.URL.absoluteString;
|
|
|
|
// TODO: We should use the WebKit PostMessage API and the
|
|
// `didReceiveScriptMessage` delegate to manage the JS<->Native bridge
|
|
if ([urlString hasPrefix:@"js:"])
|
|
{
|
|
// Listen only to the scheme of the JS<->Native bridge
|
|
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByRemovingPercentEncoding];
|
|
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
|
NSError *error;
|
|
NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers
|
|
error:&error];
|
|
if (!error)
|
|
{
|
|
// Retrieve the js event payload data
|
|
NSDictionary *eventData;
|
|
MXJSONModelSetDictionary(eventData, parameters[@"event.data"]);
|
|
|
|
NSString *requestId;
|
|
MXJSONModelSetString(requestId, eventData[@"_id"]);
|
|
|
|
if (requestId)
|
|
{
|
|
[self onPostMessageRequest:requestId data:eventData];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[WidgetVC] shouldStartLoadWithRequest: ERROR: Missing request id in postMessage API %@", parameters);
|
|
}
|
|
}
|
|
|
|
decisionHandler(WKNavigationActionPolicyCancel);
|
|
return;
|
|
}
|
|
|
|
if (navigationAction.navigationType == WKNavigationTypeLinkActivated)
|
|
{
|
|
NSURL *linkURL = navigationAction.request.URL;
|
|
|
|
// Open links outside the app
|
|
[[UIApplication sharedApplication] vc_open:linkURL completionHandler:^(BOOL success) {
|
|
if (!success)
|
|
{
|
|
MXLogDebug(@"[WidgetVC] webView:decidePolicyForNavigationAction:decisionHandler fail to open external link: %@", linkURL);
|
|
}
|
|
}];
|
|
decisionHandler(WKNavigationActionPolicyCancel);
|
|
return;
|
|
}
|
|
|
|
decisionHandler(WKNavigationActionPolicyAllow);
|
|
}
|
|
|
|
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error
|
|
{
|
|
// Filter out the users's scalar token
|
|
NSString *errorDescription = error.description;
|
|
errorDescription = [self stringByReplacingScalarTokenInString:errorDescription byScalarToken:@"..."];
|
|
|
|
MXLogDebug(@"[WidgetVC] didFailLoadWithError: %@", errorDescription);
|
|
|
|
[self stopActivityIndicator];
|
|
[self showErrorAsAlert:error];
|
|
}
|
|
|
|
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
|
|
|
|
if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]])
|
|
{
|
|
NSHTTPURLResponse * response = (NSHTTPURLResponse *)navigationResponse.response;
|
|
if (response.statusCode != 200)
|
|
{
|
|
MXLogDebug(@"[WidgetVC] decidePolicyForNavigationResponse: statusCode: %@", @(response.statusCode));
|
|
}
|
|
|
|
if (response.statusCode == 403 && [[WidgetManager sharedManager] isScalarUrl:self.URL forUser:self.widget.mxSession.myUser.userId])
|
|
{
|
|
[self fixScalarToken];
|
|
}
|
|
}
|
|
decisionHandler(WKNavigationResponsePolicyAllow);
|
|
}
|
|
|
|
#pragma mark - postMessage API
|
|
|
|
- (void)onPostMessageRequest:(NSString*)requestId data:(NSDictionary*)requestData
|
|
{
|
|
NSString *action;
|
|
MXJSONModelSetString(action, requestData[@"action"]);
|
|
|
|
if ([@"m.sticker" isEqualToString:action])
|
|
{
|
|
// Extract the sticker event content and send it as is
|
|
|
|
// The key should be "data" according to https://docs.google.com/document/d/1uPF7XWY_dXTKVKV7jZQ2KmsI19wn9-kFRgQ1tFQP7wQ/edit?usp=sharing
|
|
// TODO: Fix it once spec is finalised
|
|
NSDictionary *widgetData;
|
|
NSDictionary *stickerContent;
|
|
MXJSONModelSetDictionary(widgetData, requestData[@"widgetData"]);
|
|
if (widgetData)
|
|
{
|
|
MXJSONModelSetDictionary(stickerContent, widgetData[@"content"]);
|
|
}
|
|
|
|
if (stickerContent)
|
|
{
|
|
// Let the data source manage the sending cycle
|
|
[_roomDataSource sendEventOfType:kMXEventTypeStringSticker content:stickerContent success:nil failure:nil];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[WidgetVC] onPostMessageRequest: ERROR: Invalid content for m.sticker: %@", requestData);
|
|
}
|
|
|
|
// Consider we are done with the sticker picker widget
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}
|
|
else if ([@"integration_manager_open" isEqualToString:action])
|
|
{
|
|
NSDictionary *widgetData;
|
|
NSString *integType, *integId;
|
|
MXJSONModelSetDictionary(widgetData, requestData[@"widgetData"]);
|
|
if (widgetData)
|
|
{
|
|
MXJSONModelSetString(integType, widgetData[@"integType"]);
|
|
MXJSONModelSetString(integId, widgetData[@"integId"]);
|
|
}
|
|
|
|
if (integType && integId)
|
|
{
|
|
// Open the integration manager requested page
|
|
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc]
|
|
initForMXSession:self.roomDataSource.mxSession
|
|
inRoom:self.roomDataSource.roomId
|
|
screen:[IntegrationManagerViewController screenForWidget:integType]
|
|
widgetId:integId];
|
|
|
|
[self presentViewController:modularVC animated:NO completion:nil];
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[WidgetVC] onPostMessageRequest: ERROR: Invalid content for integration_manager_open: %@", requestData);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MXLogDebug(@"[WidgetVC] onPostMessageRequest: ERROR: Unsupported action: %@: %@", action, requestData);
|
|
}
|
|
}
|
|
|
|
- (void)sendBoolResponse:(BOOL)response toRequest:(NSString*)requestId
|
|
{
|
|
// Convert BOOL to "true" or "false"
|
|
NSString *js = [NSString stringWithFormat:kJavascriptSendResponseToPostMessageAPI,
|
|
requestId,
|
|
response ? @"true" : @"false"];
|
|
|
|
[webView evaluateJavaScript:js completionHandler:nil];
|
|
}
|
|
|
|
- (void)sendIntegerResponse:(NSUInteger)response toRequest:(NSString*)requestId
|
|
{
|
|
NSString *js = [NSString stringWithFormat:kJavascriptSendResponseToPostMessageAPI,
|
|
requestId,
|
|
@(response)];
|
|
|
|
[webView evaluateJavaScript:js completionHandler:nil];
|
|
}
|
|
|
|
- (void)sendNSObjectResponse:(NSObject*)response toRequest:(NSString*)requestId
|
|
{
|
|
NSString *jsString;
|
|
|
|
if (response)
|
|
{
|
|
// Convert response into a JS object through a JSON string
|
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:response
|
|
options:0
|
|
error:0];
|
|
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
|
|
|
|
jsString = [NSString stringWithFormat:@"JSON.parse('%@')", jsonString];
|
|
}
|
|
else
|
|
{
|
|
jsString = @"null";
|
|
}
|
|
|
|
NSString *js = [NSString stringWithFormat:kJavascriptSendResponseToPostMessageAPI,
|
|
requestId,
|
|
jsString];
|
|
|
|
[webView evaluateJavaScript:js completionHandler:nil];
|
|
}
|
|
|
|
- (void)sendError:(NSString*)message toRequest:(NSString*)requestId
|
|
{
|
|
MXLogDebug(@"[WidgetVC] sendError: Action %@ failed with message: %@", requestId, message);
|
|
|
|
// TODO: JS has an additional optional parameter: nestedError
|
|
[self sendNSObjectResponse:@{
|
|
@"error": @{
|
|
@"message": message
|
|
}
|
|
}
|
|
toRequest:requestId];
|
|
}
|
|
|
|
#pragma mark - Private methods
|
|
|
|
- (NSString *)stringByReplacingScalarTokenInString:(NSString*)string byScalarToken:(NSString*)scalarToken
|
|
{
|
|
if (!string)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"scalar_token=\\w*"
|
|
options:NSRegularExpressionCaseInsensitive error:nil];
|
|
return [regex stringByReplacingMatchesInString:string
|
|
options:0
|
|
range:NSMakeRange(0, string.length)
|
|
withTemplate:[NSString stringWithFormat:@"scalar_token=%@", scalarToken]];
|
|
}
|
|
|
|
/**
|
|
Reset the scalar token used in the webview URL.
|
|
*/
|
|
- (void)fixScalarToken
|
|
{
|
|
MXLogDebug(@"[WidgetVC] fixScalarToken");
|
|
|
|
self->webView.hidden = YES;
|
|
|
|
// Get a fresh new scalar token
|
|
[WidgetManager.sharedManager deleteDataForUser:widget.mxSession.myUser.userId];
|
|
|
|
MXWeakify(self);
|
|
[WidgetManager.sharedManager getScalarTokenForMXSession:widget.mxSession validate:NO success:^(NSString *scalarToken) {
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
MXLogDebug(@"[WidgetVC] fixScalarToken: DONE");
|
|
[self loadDataWithScalarToken:scalarToken];
|
|
|
|
} failure:^(NSError *error) {
|
|
MXLogDebug(@"[WidgetVC] fixScalarToken: Error: %@", error);
|
|
|
|
if ([error.domain isEqualToString:WidgetManagerErrorDomain]
|
|
&& error.code == WidgetManagerErrorCodeTermsNotSigned)
|
|
{
|
|
[self presentTerms];
|
|
}
|
|
else
|
|
{
|
|
[self showErrorAsAlert:error];
|
|
}
|
|
}];
|
|
}
|
|
|
|
- (void)loadDataWithScalarToken:(NSString*)scalarToken
|
|
{
|
|
self.URL = [self stringByReplacingScalarTokenInString:self.URL byScalarToken:scalarToken];
|
|
|
|
self->webView.hidden = NO;
|
|
}
|
|
|
|
|
|
|
|
#pragma mark - Service terms
|
|
|
|
- (void)presentTerms
|
|
{
|
|
if (self.serviceTermsModalCoordinatorBridgePresenter)
|
|
{
|
|
return;
|
|
}
|
|
|
|
WidgetManagerConfig *config = [[WidgetManager sharedManager] configForUser:widget.mxSession.myUser.userId];
|
|
|
|
MXLogDebug(@"[WidgetVC] presentTerms for %@", config.baseUrl);
|
|
|
|
ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter = [[ServiceTermsModalCoordinatorBridgePresenter alloc] initWithSession:widget.mxSession baseUrl:config.baseUrl
|
|
serviceType:MXServiceTypeIntegrationManager
|
|
accessToken:config.scalarToken];
|
|
serviceTermsModalCoordinatorBridgePresenter.delegate = self;
|
|
|
|
[serviceTermsModalCoordinatorBridgePresenter presentFrom:self animated:YES];
|
|
self.serviceTermsModalCoordinatorBridgePresenter = serviceTermsModalCoordinatorBridgePresenter;
|
|
}
|
|
|
|
- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidAccept:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
|
|
{
|
|
MXWeakify(self);
|
|
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
|
MXStrongifyAndReturnIfNil(self);
|
|
|
|
WidgetManagerConfig *config = [[WidgetManager sharedManager] configForUser:self->widget.mxSession.myUser.userId];
|
|
[self loadDataWithScalarToken:config.scalarToken];
|
|
}];
|
|
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidDecline:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter session:(MXSession * _Nonnull)session
|
|
{
|
|
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
|
[self withdrawViewControllerAnimated:YES completion:nil];
|
|
}];
|
|
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidClose:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
|
|
{
|
|
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
|
}
|
|
|
|
@end
|