mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-24 18:42:47 +02:00
Merge branch 'develop' into callkit
This commit is contained in:
@@ -61,6 +61,11 @@
|
||||
self.view.backgroundColor = kRiotPrimaryBgColor;
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.navigationBar.tintColor = kRiotSecondaryBgColor;
|
||||
self.navigationBar.titleTextAttributes = @{NSForegroundColorAttributeName: kRiotPrimaryTextColor};
|
||||
self.backButton.tintColor = kRiotColorGreen;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
|
||||
@@ -176,6 +176,7 @@
|
||||
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
[self.authInputsView customizeViewRendering];
|
||||
|
||||
@@ -722,6 +723,27 @@
|
||||
// Hide the custom server details in order to save customized inputs
|
||||
[self hideCustomServers:YES];
|
||||
|
||||
// Create DM with Riot-bot on new account creation.
|
||||
if (self.authType == MXKAuthenticationTypeRegister)
|
||||
{
|
||||
MXKAccount *account = [[MXKAccountManager sharedManager] accountForUserId:userId];
|
||||
|
||||
[account.mxSession createRoom:nil
|
||||
visibility:kMXRoomDirectoryVisibilityPrivate
|
||||
roomAlias:nil
|
||||
topic:nil
|
||||
invite:@[@"@riot-bot:matrix.org"]
|
||||
invite3PID:nil
|
||||
isDirect:YES
|
||||
preset:kMXRoomPresetTrustedPrivateChat
|
||||
success:nil
|
||||
failure:^(NSError *error) {
|
||||
|
||||
NSLog(@"[AuthenticationVC] Create chat with riot-bot failed");
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
// Remove auth view controller on successful login
|
||||
if (self.navigationController)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
@property (nonatomic) BOOL sendLogs;
|
||||
@property (nonatomic) BOOL sendScreenshot;
|
||||
|
||||
@property (weak, nonatomic) IBOutlet UIView *overlayView;
|
||||
|
||||
@end
|
||||
|
||||
@implementation BugReportViewController
|
||||
@@ -137,6 +139,10 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.overlayView.backgroundColor = kRiotOverlayColor;
|
||||
self.overlayView.alpha = 1.0;
|
||||
|
||||
self.containerView.backgroundColor = kRiotPrimaryBgColor;
|
||||
self.sendingContainer.backgroundColor = kRiotPrimaryBgColor;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
|
||||
<device id="retina5_5" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
@@ -17,6 +17,7 @@
|
||||
<outlet property="containerView" destination="7U4-br-xRl" id="kJI-mL-pkw"/>
|
||||
<outlet property="descriptionLabel" destination="Q2l-Yi-SlQ" id="VPO-0N-huQ"/>
|
||||
<outlet property="logsDescriptionLabel" destination="ggt-kq-Zy9" id="3Nl-m3-1EE"/>
|
||||
<outlet property="overlayView" destination="CXZ-fI-kPd" id="ZJb-0n-Tmf"/>
|
||||
<outlet property="scrollView" destination="4fS-3N-tbW" id="Dsn-gw-VuW"/>
|
||||
<outlet property="scrollViewBottomConstraint" destination="fnt-1e-ZW4" id="W1B-1m-h13"/>
|
||||
<outlet property="sendButton" destination="z8A-7B-jAi" id="VSX-a9-yfs"/>
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
|
||||
#import "AvatarGenerator.h"
|
||||
|
||||
#import "MXRoom+Riot.h"
|
||||
|
||||
#import "UsersDevicesViewController.h"
|
||||
|
||||
#import "RiotNavigationController.h"
|
||||
@@ -101,6 +99,7 @@
|
||||
self.view.backgroundColor = kRiotPrimaryBgColor;
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.callerNameLabel.textColor = kRiotPrimaryTextColor;
|
||||
self.callStatusLabel.textColor = kRiotTopicTextColor;
|
||||
@@ -358,7 +357,7 @@
|
||||
}
|
||||
else if (self.mxCall.room)
|
||||
{
|
||||
return [AvatarGenerator generateAvatarForMatrixItem:self.mxCall.room.roomId withDisplayName:self.mxCall.room.riotDisplayname size:self.callerImageViewWidthConstraint.constant andFontSize:fontSize];
|
||||
return [AvatarGenerator generateAvatarForMatrixItem:self.mxCall.room.roomId withDisplayName:self.mxCall.room.summary.displayname size:self.callerImageViewWidthConstraint.constant andFontSize:fontSize];
|
||||
}
|
||||
|
||||
return [UIImage imageNamed:@"placeholder"];
|
||||
@@ -387,7 +386,7 @@
|
||||
}
|
||||
else if (self.mxCall.isConferenceCall)
|
||||
{
|
||||
peerDisplayName = self.mxCall.room.riotDisplayname;
|
||||
peerDisplayName = self.mxCall.room.summary.displayname;
|
||||
peerAvatarURL = self.mxCall.room.state.avatar;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,6 +224,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.headerView.backgroundColor = kRiotSecondaryBgColor;
|
||||
self.contactNameLabel.textColor = kRiotPrimaryTextColor;
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.contactsTableView.backgroundColor = ((self.contactsTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.searchBar.barStyle = kRiotDesignSearchBarStyle;
|
||||
self.searchBar.tintColor = kRiotDesignSearchBarTintColor;
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.searchTableView.backgroundColor = ((self.searchTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -79,6 +79,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.searchTableView.backgroundColor = ((self.searchTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.searchBar.barStyle = kRiotDesignSearchBarStyle;
|
||||
self.searchBar.tintColor = kRiotDesignSearchBarTintColor;
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
self.assetsCollectionView.backgroundColor = kRiotPrimaryBgColor;
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
}
|
||||
|
||||
- (UIStatusBarStyle)preferredStatusBarStyle
|
||||
|
||||
@@ -183,6 +183,7 @@ static void *RecordingContext = &RecordingContext;
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.cameraVideoCaptureProgressView.progressColor = kRiotPrimaryBgColor;
|
||||
self.cameraVideoCaptureProgressView.unprogressColor = [UIColor clearColor];
|
||||
|
||||
@@ -96,6 +96,10 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.overlayView.backgroundColor = kRiotOverlayColor;
|
||||
self.overlayView.alpha = 1.0;
|
||||
|
||||
self.titleLabel.textColor = kRiotPrimaryTextColor;
|
||||
self.containerView.backgroundColor = kRiotPrimaryBgColor;
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Use the primary bg color for the recents table view in plain style.
|
||||
self.recentsTableView.backgroundColor = kRiotPrimaryBgColor;
|
||||
|
||||
@@ -73,6 +73,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.searchTableView.backgroundColor = ((self.searchTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -111,6 +111,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.bubblesTableView.backgroundColor = ((self.bubblesTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -209,6 +209,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.memberHeaderView.backgroundColor = kRiotSecondaryBgColor;
|
||||
self.roomMemberNameLabel.textColor = kRiotPrimaryTextColor;
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.searchTableView.backgroundColor = ((self.searchTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -158,10 +158,11 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
[self refreshSearchBarItemsColor:_searchBarView];
|
||||
|
||||
_searchBarHeaderBorder.backgroundColor = kRiotColorSilver;
|
||||
_searchBarHeaderBorder.backgroundColor = kRiotAuxiliaryColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
// Add the Vector background image when search bar is empty
|
||||
// Add the Riot background image when search bar is empty
|
||||
[self addBackgroundImageViewToView:self.view];
|
||||
|
||||
// Initialize here the data sources if a matrix session has been already set.
|
||||
@@ -72,6 +72,18 @@
|
||||
self.searchBar.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
||||
}
|
||||
|
||||
- (void)userInterfaceThemeDidChange
|
||||
{
|
||||
[super userInterfaceThemeDidChange];
|
||||
|
||||
UIImageView *backgroundImageView = self.backgroundImageView;
|
||||
if (backgroundImageView)
|
||||
{
|
||||
UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:kRiotKeyboardColor];
|
||||
backgroundImageView.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#import "Tools.h"
|
||||
|
||||
#import "MXRoom+Riot.h"
|
||||
#import "MXRoomSummary+Riot.h"
|
||||
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@@ -246,6 +247,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
@@ -1964,6 +1966,9 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
}
|
||||
|
||||
cell = roomNotifCell;
|
||||
|
||||
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
||||
[cell layoutIfNeeded];
|
||||
}
|
||||
else if (row == ROOM_SETTINGS_MAIN_SECTION_ROW_PHOTO)
|
||||
{
|
||||
@@ -1994,7 +1999,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
}
|
||||
else
|
||||
{
|
||||
[mxRoom setRoomAvatarImageIn:roomPhotoCell.mxkImageView];
|
||||
[mxRoom.summary setRoomAvatarImageIn:roomPhotoCell.mxkImageView];
|
||||
|
||||
roomPhotoCell.userInteractionEnabled = (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomAvatar]);
|
||||
roomPhotoCell.mxkImageView.alpha = roomPhotoCell.userInteractionEnabled ? 1.0f : 0.5f;
|
||||
@@ -2181,6 +2186,9 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
directoryVisibilitySwitch.enabled = (oneSelfPowerLevel >= powerLevels.stateDefault);
|
||||
|
||||
cell = directoryToggleCell;
|
||||
|
||||
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
||||
[cell layoutIfNeeded];
|
||||
}
|
||||
else if (indexPath.row == missingAddressWarningIndex)
|
||||
{
|
||||
@@ -2491,6 +2499,9 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
roomEncryptionBlacklistUnverifiedDevicesSwitch.on = blacklistUnverifiedDevices;
|
||||
|
||||
cell = roomBlacklistUnverifiedDevicesCell;
|
||||
|
||||
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
||||
[cell layoutIfNeeded];
|
||||
}
|
||||
else if (indexPath.row == 2)
|
||||
{
|
||||
@@ -2547,6 +2558,9 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti
|
||||
roomEncryptionSwitch.on = ([updatedItemsDict objectForKey:kRoomSettingsEncryptionKey] != nil);
|
||||
|
||||
cell = roomEncryptionCell;
|
||||
|
||||
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
||||
[cell layoutIfNeeded];
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
|
||||
#import "MXRoom+Riot.h"
|
||||
|
||||
#import "IntegrationManagerViewController.h"
|
||||
#import "WidgetViewController.h"
|
||||
|
||||
@interface RoomViewController ()
|
||||
{
|
||||
// The expanded header
|
||||
@@ -180,9 +183,9 @@
|
||||
// Tell whether the view controller is appeared or not.
|
||||
BOOL isAppeared;
|
||||
|
||||
// The search bar buttom item back up.
|
||||
UIBarButtonItem *searchBarButtonItem;
|
||||
|
||||
// The right bar button items back up.
|
||||
NSArray<UIBarButtonItem *> *rightBarButtonItems;
|
||||
|
||||
// Observe kRiotDesignValuesDidChangeThemeNotification to handle user interface theme change.
|
||||
id kRiotDesignValuesDidChangeThemeNotificationObserver;
|
||||
}
|
||||
@@ -360,9 +363,12 @@
|
||||
[self setEventDetailsViewClass:EventDetailsView.class];
|
||||
|
||||
// Update navigation bar items
|
||||
self.navigationItem.rightBarButtonItem.target = self;
|
||||
self.navigationItem.rightBarButtonItem.action = @selector(onButtonPressed:);
|
||||
|
||||
for (UIBarButtonItem *barButtonItem in self.navigationItem.rightBarButtonItems)
|
||||
{
|
||||
barButtonItem.target = self;
|
||||
barButtonItem.action = @selector(onButtonPressed:);
|
||||
}
|
||||
|
||||
// Prepare missed dicussion badge
|
||||
missedDiscussionsBarButtonCustomView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 21)];
|
||||
missedDiscussionsBarButtonCustomView.backgroundColor = [UIColor clearColor];
|
||||
@@ -417,6 +423,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Prepare jump to last unread banner
|
||||
self.jumpToLastUnreadBannerContainer.backgroundColor = kRiotPrimaryBgColor;
|
||||
@@ -1046,8 +1053,11 @@
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
searchBarButtonItem = nil;
|
||||
self.navigationItem.rightBarButtonItem.enabled = NO;
|
||||
rightBarButtonItems = nil;
|
||||
for (UIBarButtonItem *barButtonItem in self.navigationItem.rightBarButtonItems)
|
||||
{
|
||||
barButtonItem.enabled = NO;
|
||||
}
|
||||
|
||||
if (currentAlert)
|
||||
{
|
||||
@@ -1150,17 +1160,20 @@
|
||||
|
||||
- (void)refreshRoomTitle
|
||||
{
|
||||
if (searchBarButtonItem && !self.navigationItem.rightBarButtonItem)
|
||||
if (rightBarButtonItems && !self.navigationItem.rightBarButtonItems)
|
||||
{
|
||||
// Restore by default the search bar button.
|
||||
self.navigationItem.rightBarButtonItem = searchBarButtonItem;
|
||||
self.navigationItem.rightBarButtonItems = rightBarButtonItems;
|
||||
}
|
||||
|
||||
// Set the right room title view
|
||||
if (self.isRoomPreview)
|
||||
{
|
||||
// Disable the search button
|
||||
self.navigationItem.rightBarButtonItem.enabled = NO;
|
||||
// Disable the right buttons
|
||||
for (UIBarButtonItem *barButtonItem in self.navigationItem.rightBarButtonItems)
|
||||
{
|
||||
barButtonItem.enabled = NO;
|
||||
}
|
||||
|
||||
[self showPreviewHeader:YES];
|
||||
}
|
||||
@@ -1170,8 +1183,18 @@
|
||||
|
||||
if (self.roomDataSource.isLive)
|
||||
{
|
||||
// Enable the search button
|
||||
self.navigationItem.rightBarButtonItem.enabled = YES;
|
||||
// Enable the right buttons (Search and Integrations)
|
||||
for (UIBarButtonItem *barButtonItem in self.navigationItem.rightBarButtonItems)
|
||||
{
|
||||
barButtonItem.enabled = YES;
|
||||
}
|
||||
|
||||
BOOL matrixAppsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"matrixApps"];
|
||||
if (!matrixAppsEnabled && self.navigationItem.rightBarButtonItems.count == 2)
|
||||
{
|
||||
// If the setting is disabled, do not show the icon
|
||||
self.navigationItem.rightBarButtonItems = @[self.navigationItem.rightBarButtonItem];
|
||||
}
|
||||
|
||||
// Do not change title view class here if the expanded header is visible.
|
||||
if (self.expandedHeaderContainer.hidden)
|
||||
@@ -1191,8 +1214,8 @@
|
||||
else
|
||||
{
|
||||
// Remove the search button temporarily
|
||||
searchBarButtonItem = self.navigationItem.rightBarButtonItem;
|
||||
self.navigationItem.rightBarButtonItem = nil;
|
||||
rightBarButtonItems = self.navigationItem.rightBarButtonItems;
|
||||
self.navigationItem.rightBarButtonItems = nil;
|
||||
|
||||
[self setRoomTitleViewClass:SimpleRoomTitleView.class];
|
||||
self.titleView.editable = NO;
|
||||
@@ -2850,10 +2873,35 @@
|
||||
|
||||
- (IBAction)onButtonPressed:(id)sender
|
||||
{
|
||||
// Search button
|
||||
if (sender == self.navigationItem.rightBarButtonItem)
|
||||
{
|
||||
[self performSegueWithIdentifier:@"showRoomSearch" sender:self];
|
||||
}
|
||||
// Matrix Apps button
|
||||
else if (self.navigationItem.rightBarButtonItems.count == 2 && sender == self.navigationItem.rightBarButtonItems[1])
|
||||
{
|
||||
// Temporary code to test `WidgetViewController`
|
||||
// TODO: remove it
|
||||
// NSArray<Widget *> *widgets = [[WidgetManager sharedManager] widgetsInRoom:self.roomDataSource.room];
|
||||
// if (widgets.count)
|
||||
// {
|
||||
// // Hide back button title
|
||||
// self.navigationItem.backBarButtonItem =[[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
|
||||
//
|
||||
// WidgetViewController *widgetVC = [[WidgetViewController alloc] initForWidget:widgets[0]];
|
||||
// [self.navigationController pushViewController:widgetVC animated:YES];
|
||||
// }
|
||||
// else
|
||||
{
|
||||
IntegrationManagerViewController *modularVC = [[IntegrationManagerViewController alloc] initForMXSession:self.roomDataSource.mxSession
|
||||
inRoom:self.roomDataSource.roomId
|
||||
screen:kIntegrationManagerMainScreen
|
||||
widgetId:nil];
|
||||
|
||||
[self presentViewController:modularVC animated:NO completion:nil];
|
||||
}
|
||||
}
|
||||
else if (sender == self.jumpToLastUnreadButton)
|
||||
{
|
||||
// Hide expanded header to restore navigation bar settings.
|
||||
|
||||
@@ -77,6 +77,11 @@ limitations under the License.
|
||||
@param viewControllers the list of viewControllers to display.
|
||||
@param defaultSelected index of the default selected UIViewController in the list.
|
||||
*/
|
||||
- (void)initWithTitles:(NSArray*)titles viewControllers:(NSArray*)viewControllers defaultSelected:(NSUInteger)index;
|
||||
- (void)initWithTitles:(NSArray*)titles viewControllers:(NSArray*)viewControllers defaultSelected:(NSUInteger)defaultSelected;
|
||||
|
||||
/**
|
||||
Callback used to take into account the change of the user interface theme.
|
||||
*/
|
||||
- (void)userInterfaceThemeDidChange;
|
||||
|
||||
@end
|
||||
|
||||
@@ -71,11 +71,11 @@
|
||||
@param viewControllers the list of viewControllers to display.
|
||||
@param defaultSelected index of the default selected UIViewController in the list.
|
||||
*/
|
||||
- (void)initWithTitles:(NSArray*)titles viewControllers:(NSArray*)someViewControllers defaultSelected:(NSUInteger)index
|
||||
- (void)initWithTitles:(NSArray*)titles viewControllers:(NSArray*)someViewControllers defaultSelected:(NSUInteger)defaultSelected
|
||||
{
|
||||
viewControllers = someViewControllers;
|
||||
sectionTitles = titles;
|
||||
_selectedIndex = index;
|
||||
_selectedIndex = defaultSelected;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
@@ -172,6 +172,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
self.view.backgroundColor = kRiotPrimaryBgColor;
|
||||
}
|
||||
|
||||
@@ -105,8 +105,9 @@ enum
|
||||
|
||||
enum
|
||||
{
|
||||
#ifdef USE_JITSI_WIDGET
|
||||
LABS_MATRIX_APPS_INDEX = 0,
|
||||
#ifdef USE_JITSI_WIDGET
|
||||
LABS_USE_JITSI_WIDGET_INDEX,
|
||||
#endif
|
||||
LABS_CRYPTO_INDEX,
|
||||
LABS_COUNT
|
||||
@@ -314,6 +315,7 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
@@ -1269,6 +1271,8 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
cell.alpha = 1.0f;
|
||||
cell.userInteractionEnabled = YES;
|
||||
|
||||
[cell layoutIfNeeded];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -1281,6 +1285,9 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
|
||||
cell.mxkLabel.textColor = kRiotPrimaryTextColor;
|
||||
|
||||
// Force layout before reusing a cell (fix switch displayed outside the screen)
|
||||
[cell layoutIfNeeded];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
@@ -1331,6 +1338,12 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
signOutCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
||||
// Do not move this line in prepareForReuse because of https://github.com/vector-im/riot-ios/issues/1323
|
||||
signOutCell.mxkButton.titleLabel.text = nil;
|
||||
}
|
||||
|
||||
NSString* title = NSLocalizedStringFromTable(@"settings_sign_out", @"Vector", nil);
|
||||
|
||||
@@ -1909,6 +1922,11 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
markAllBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
||||
markAllBtnCell.mxkButton.titleLabel.text = nil;
|
||||
}
|
||||
|
||||
NSString *btnTitle = NSLocalizedStringFromTable(@"settings_mark_all_as_read", @"Vector", nil);
|
||||
[markAllBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
||||
@@ -1929,6 +1947,11 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
clearCacheBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
||||
clearCacheBtnCell.mxkButton.titleLabel.text = nil;
|
||||
}
|
||||
|
||||
NSString *btnTitle = NSLocalizedStringFromTable(@"settings_clear_cache", @"Vector", nil);
|
||||
[clearCacheBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
||||
@@ -1949,6 +1972,11 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
reportBugBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
||||
reportBugBtnCell.mxkButton.titleLabel.text = nil;
|
||||
}
|
||||
|
||||
NSString *btnTitle = NSLocalizedStringFromTable(@"settings_report_bug", @"Vector", nil);
|
||||
[reportBugBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
||||
@@ -1965,11 +1993,23 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
}
|
||||
else if (section == SETTINGS_SECTION_LABS_INDEX)
|
||||
{
|
||||
#ifdef USE_JITSI_WIDGET
|
||||
if (row == LABS_MATRIX_APPS_INDEX)
|
||||
{
|
||||
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
|
||||
|
||||
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_labs_matrix_apps", @"Vector", nil);
|
||||
labelAndSwitchCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"matrixApps"];
|
||||
|
||||
[labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside];
|
||||
[labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleLabsMatrixApps:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
cell = labelAndSwitchCell;
|
||||
}
|
||||
#ifdef USE_JITSI_WIDGET
|
||||
else if (row == LABS_USE_JITSI_WIDGET_INDEX)
|
||||
{
|
||||
MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath];
|
||||
|
||||
labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_labs_create_conference_with_jitsi", @"Vector", nil);
|
||||
labelAndSwitchCell.mxkSwitch.on = [[NSUserDefaults standardUserDefaults] boolForKey:@"createConferenceCallsWithJitsi"];
|
||||
|
||||
@@ -2052,6 +2092,11 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
{
|
||||
exportKeysBtnCell = [[MXKTableViewCellWithButton alloc] init];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix https://github.com/vector-im/riot-ios/issues/1354
|
||||
exportKeysBtnCell.mxkButton.titleLabel.text = nil;
|
||||
}
|
||||
|
||||
NSString *btnTitle = NSLocalizedStringFromTable(@"settings_crypto_export", @"Vector", nil);
|
||||
[exportKeysBtnCell.mxkButton setTitle:btnTitle forState:UIControlStateNormal];
|
||||
@@ -2747,6 +2792,19 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)();
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toggleLabsMatrixApps:(id)sender
|
||||
{
|
||||
if (sender && [sender isKindOfClass:UISwitch.class])
|
||||
{
|
||||
UISwitch *switchButton = (UISwitch*)sender;
|
||||
|
||||
[[NSUserDefaults standardUserDefaults] setBool:switchButton.isOn forKey:@"matrixApps"];
|
||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||
|
||||
[self.tableView reloadData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)toggleJitsiForConference:(id)sender
|
||||
{
|
||||
if (sender && [sender isKindOfClass:UISwitch.class])
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
|
||||
[self refreshSearchBarItemsColor:_searchBarView];
|
||||
|
||||
_searchBarHeaderBorder.backgroundColor = kRiotColorSilver;
|
||||
_searchBarHeaderBorder.backgroundColor = kRiotAuxiliaryColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.contactsTableView.backgroundColor = ((self.contactsTableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
|
||||
[super viewDidLoad];
|
||||
|
||||
// Add the Vector background image when search bar is empty
|
||||
// Add the Riot background image when search bar is empty
|
||||
[self addBackgroundImageViewToView:self.view];
|
||||
|
||||
// Initialize here the data sources if a matrix session has been already set.
|
||||
@@ -107,6 +107,18 @@
|
||||
[super showSearch:NO];
|
||||
}
|
||||
|
||||
- (void)userInterfaceThemeDidChange
|
||||
{
|
||||
[super userInterfaceThemeDidChange];
|
||||
|
||||
UIImageView *backgroundImageView = self.backgroundImageView;
|
||||
if (backgroundImageView)
|
||||
{
|
||||
UIImage *image = [MXKTools paintImage:backgroundImageView.image withColor:kRiotKeyboardColor];
|
||||
backgroundImageView.image = image;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
{
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
// Check the table view style to select its bg color.
|
||||
self.tableView.backgroundColor = ((self.tableView.style == UITableViewStylePlain) ? kRiotPrimaryBgColor : kRiotSecondaryBgColor);
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
self.view.backgroundColor = kRiotPrimaryBgColor;
|
||||
self.defaultBarTintColor = kRiotSecondaryBgColor;
|
||||
self.barTitleColor = kRiotPrimaryTextColor;
|
||||
self.activityIndicator.backgroundColor = kRiotOverlayColor;
|
||||
|
||||
webView.backgroundColor = kRiotPrimaryBgColor;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "WebViewViewController.h"
|
||||
|
||||
#import <MatrixSDK/MatrixSDK.h>
|
||||
|
||||
FOUNDATION_EXPORT NSString *const kIntegrationManagerMainScreen;
|
||||
FOUNDATION_EXPORT NSString *const kIntegrationManagerAddIntegrationScreen;
|
||||
|
||||
/**
|
||||
`IntegrationManagerViewController` displays the Modular integration manager webapp
|
||||
into a webview.
|
||||
*/
|
||||
@interface IntegrationManagerViewController : WebViewViewController <UIWebViewDelegate>
|
||||
|
||||
/**
|
||||
Initialise with params for the Modular interface webapp.
|
||||
|
||||
@param mxSession the session to use.
|
||||
@param roomId the room where to set up widgets.
|
||||
@param screen the screen to display in the Modular interface webapp. Can be nil.
|
||||
@param widgetId the id of the widget in case of widget configuration edition. Can be nil.
|
||||
*/
|
||||
- (instancetype)initForMXSession:(MXSession*)mxSession inRoom:(NSString*)roomId screen:(NSString*)screen widgetId:(NSString*)widgetId;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,741 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "IntegrationManagerViewController.h"
|
||||
|
||||
#import "WidgetManager.h"
|
||||
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
NSString *const kIntegrationManagerMainScreen = nil;
|
||||
NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
|
||||
NSString *const kJavascriptSendResponseToModular = @"riotIOS.sendResponse('%@', %@);";
|
||||
|
||||
|
||||
@interface IntegrationManagerViewController ()
|
||||
{
|
||||
MXSession *mxSession;
|
||||
NSString *roomId;
|
||||
NSString *screen;
|
||||
NSString *widgetId;
|
||||
NSString *scalarToken;
|
||||
|
||||
MXHTTPOperation *operation;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation IntegrationManagerViewController
|
||||
|
||||
- (instancetype)initForMXSession:(MXSession *)theMXSession inRoom:(NSString *)theRoomId screen:(NSString *)theScreen widgetId:(NSString *)theWidgetId
|
||||
{
|
||||
self = [super init];
|
||||
if (self)
|
||||
{
|
||||
mxSession = theMXSession;
|
||||
roomId = theRoomId;
|
||||
screen = theScreen;
|
||||
widgetId = theWidgetId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)destroy
|
||||
{
|
||||
[super destroy];
|
||||
|
||||
[operation cancel];
|
||||
operation = nil;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
webView.scalesPageToFit = NO;
|
||||
webView.scrollView.bounces = NO;
|
||||
|
||||
webView.delegate = self;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
if (!self.URL && !operation)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[self startActivityIndicator];
|
||||
|
||||
// Make sure we a scalar token
|
||||
operation = [[WidgetManager sharedManager] getScalarTokenForMXSession:mxSession success:^(NSString *theScalarToken) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
if (self)
|
||||
{
|
||||
self->operation = nil;
|
||||
[self stopActivityIndicator];
|
||||
|
||||
scalarToken = theScalarToken;
|
||||
|
||||
// Launch the webview on the right modular webapp page
|
||||
self.URL = [self interfaceUrl];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
|
||||
if (self)
|
||||
{
|
||||
self->operation = nil;
|
||||
[self stopActivityIndicator];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Private methods
|
||||
|
||||
/**
|
||||
Build the URL to use in the Modular interface webapp.
|
||||
*/
|
||||
- (NSString *)interfaceUrl
|
||||
{
|
||||
NSMutableString *url;
|
||||
|
||||
if (scalarToken)
|
||||
{
|
||||
url = [NSMutableString stringWithFormat:@"%@?scalar_token=%@&room_id=%@",
|
||||
[[NSUserDefaults standardUserDefaults] objectForKey:@"integrationsUiUrl"],
|
||||
[scalarToken stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
|
||||
[roomId stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
|
||||
];
|
||||
|
||||
if (screen)
|
||||
{
|
||||
[url appendString:@"&screen="];
|
||||
[url appendString:[screen stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
|
||||
if (widgetId)
|
||||
{
|
||||
[url appendString:@"&integ_id="];
|
||||
[url appendString:[widgetId stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
- (void)enableDebug
|
||||
{
|
||||
// Setup console.log() -> NSLog() route
|
||||
JSContext *ctx = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
|
||||
ctx[@"console"][@"log"] = ^(JSValue * msg) {
|
||||
NSLog(@"-- JavaScript: %@", msg);
|
||||
};
|
||||
|
||||
// Redirect all console.* logging methods to console.log
|
||||
[webView stringByEvaluatingJavaScriptFromString:@"console.debug = console.log; console.info = console.log; console.warn = console.log; console.error = console.log;"];
|
||||
}
|
||||
|
||||
#pragma mark - UIWebViewDelegate
|
||||
|
||||
-(void)webViewDidFinishLoad:(UIWebView *)theWebView
|
||||
{
|
||||
[self enableDebug];
|
||||
|
||||
// Setup js code
|
||||
NSString *path = [[NSBundle mainBundle] pathForResource:@"IntegrationManager" ofType:@"js"];
|
||||
NSString *js = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||
[webView stringByEvaluatingJavaScriptFromString:js];
|
||||
}
|
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
NSString *urlString = [[request URL] absoluteString];
|
||||
|
||||
if ([urlString hasPrefix:@"js:"])
|
||||
{
|
||||
// Listen only to scheme of the JS-UIWebView bridge
|
||||
NSString *jsonString = [[[urlString componentsSeparatedByString:@"js:"] lastObject] stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
|
||||
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
NSError *error;
|
||||
NSDictionary *parameters = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers
|
||||
error:&error];
|
||||
if (!error)
|
||||
{
|
||||
[self onMessage:parameters];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Modular postMessage API
|
||||
|
||||
- (void)onMessage:(NSDictionary*)JSData
|
||||
{
|
||||
NSDictionary *eventData;
|
||||
MXJSONModelSetDictionary(eventData, JSData[@"event.data"]);
|
||||
|
||||
NSString *roomIdInEvent, *userId, *action;
|
||||
|
||||
MXJSONModelSetString(roomIdInEvent, eventData[@"room_id"]);
|
||||
MXJSONModelSetString(userId, eventData[@"user_id"]);
|
||||
MXJSONModelSetString(action, eventData[@"action"]);
|
||||
|
||||
if ([action isEqualToString:@"close_scalar"])
|
||||
{
|
||||
[self withdrawViewControllerAnimated:YES completion:nil];
|
||||
return;
|
||||
}
|
||||
|
||||
if (!roomIdInEvent)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_missing_room_id" toEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![roomIdInEvent isEqualToString:roomId])
|
||||
{
|
||||
[self sendError:[NSString stringWithFormat:NSLocalizedStringFromTable(@"widget_integration_room_not_visible", @"Vector", nil), roomIdInEvent] toEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// These APIs don't require userId
|
||||
if ([@"join_rules_state" isEqualToString:action])
|
||||
{
|
||||
[self getJoinRules:eventData];
|
||||
return;
|
||||
}
|
||||
else if ([@"set_plumbing_state" isEqualToString:action])
|
||||
{
|
||||
[self setPlumbingState:eventData];
|
||||
return;
|
||||
}
|
||||
else if ([@"get_membership_count" isEqualToString:action])
|
||||
{
|
||||
[self getMembershipCount:eventData];
|
||||
return;
|
||||
}
|
||||
else if ([@"set_widget" isEqualToString:action])
|
||||
{
|
||||
[self setWidget:eventData];
|
||||
return;
|
||||
}
|
||||
else if ([@"get_widgets" isEqualToString:action])
|
||||
{
|
||||
[self getWidgets:eventData];
|
||||
return;
|
||||
}
|
||||
else if ([@"can_send_event" isEqualToString:action])
|
||||
{
|
||||
[self canSendEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!userId)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_missing_user_id" toEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([@"membership_state" isEqualToString:action])
|
||||
{
|
||||
[self getMembershipState:userId eventData:eventData];
|
||||
}
|
||||
else if ([@"invite" isEqualToString:action])
|
||||
{
|
||||
[self inviteUser:userId eventData:eventData];
|
||||
}
|
||||
else if ([@"bot_options" isEqualToString:action])
|
||||
{
|
||||
[self getBotOptions:userId eventData:eventData];
|
||||
}
|
||||
else if ([@"set_bot_options" isEqualToString:action])
|
||||
{
|
||||
[self setBotOptions:userId eventData:eventData];
|
||||
}
|
||||
else if ([@"set_bot_power" isEqualToString:action])
|
||||
{
|
||||
[self setBotPower:userId eventData:eventData];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[IntegrationManagerViewControllerVC] Unhandled postMessage event with action %@: %@", action, JSData);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sendBoolResponse:(BOOL)response toEvent:(NSDictionary*)eventData
|
||||
{
|
||||
// Convert BOOL to "true" or "false"
|
||||
NSString *js = [NSString stringWithFormat:kJavascriptSendResponseToModular,
|
||||
eventData[@"_id"],
|
||||
response ? @"true" : @"false"];
|
||||
|
||||
[webView stringByEvaluatingJavaScriptFromString:js];
|
||||
}
|
||||
|
||||
- (void)sendIntegerResponse:(NSUInteger)response toEvent:(NSDictionary*)eventData
|
||||
{
|
||||
NSString *js = [NSString stringWithFormat:kJavascriptSendResponseToModular,
|
||||
eventData[@"_id"],
|
||||
@(response)];
|
||||
|
||||
[webView stringByEvaluatingJavaScriptFromString:js];
|
||||
}
|
||||
|
||||
- (void)sendNSObjectResponse:(NSObject*)response toEvent:(NSDictionary*)eventData
|
||||
{
|
||||
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:kJavascriptSendResponseToModular,
|
||||
eventData[@"_id"],
|
||||
jsString];
|
||||
|
||||
[webView stringByEvaluatingJavaScriptFromString:js];
|
||||
}
|
||||
|
||||
- (void)sendError:(NSString*)message toEvent:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] sendError: Action %@ failed with message: %@", eventData[@"action"], message);
|
||||
|
||||
// TODO: JS has an additional optional parameter: nestedError
|
||||
[self sendNSObjectResponse:@{
|
||||
@"error": @{
|
||||
@"message": message
|
||||
}
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
|
||||
- (void)sendLocalisedError:(NSString*)errorKey toEvent:(NSDictionary*)eventData
|
||||
{
|
||||
[self sendError:NSLocalizedStringFromTable(errorKey, @"Vector", nil) toEvent:eventData];
|
||||
}
|
||||
|
||||
#pragma mark - Modular postMessage Implementation
|
||||
|
||||
- (MXRoom *)roomCheckWithEvent:(NSDictionary*)eventData
|
||||
{
|
||||
MXRoom *room = [mxSession roomWithRoomId:roomId];
|
||||
if (!room)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_room_not_recognised" toEvent:eventData];
|
||||
}
|
||||
|
||||
return room;
|
||||
}
|
||||
|
||||
- (void)inviteUser:(NSString*)userId eventData:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to invite %@ into room %@.", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
|
||||
if (room)
|
||||
{
|
||||
MXRoomMember *member = [room.state memberWithUserId:userId];
|
||||
if (member && member.membership == MXMembershipJoin)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
else
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[room inviteUser:userId success:^{
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_need_to_be_able_to_invite" toEvent:eventData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setWidget:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set widget in room %@.", roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
|
||||
if (room)
|
||||
{
|
||||
NSString *widget_id, *widgetType, *widgetUrl;
|
||||
NSString *widgetName; // optional
|
||||
NSDictionary *widgetData ; // optional
|
||||
|
||||
MXJSONModelSetString(widget_id, eventData[@"widget_id"]);
|
||||
MXJSONModelSetString(widgetType, eventData[@"type"]);
|
||||
MXJSONModelSetString(widgetUrl, eventData[@"url"]);
|
||||
MXJSONModelSetString(widgetName, eventData[@"name"]);
|
||||
MXJSONModelSetDictionary(widgetData, eventData[@"data"]);
|
||||
|
||||
if (!widget_id)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_unable_to_create" toEvent:eventData]; // new Error("Missing required widget fields."));
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableDictionary *widgetEventContent = [NSMutableDictionary dictionary];
|
||||
if (widgetUrl)
|
||||
{
|
||||
if (!widgetType)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_unable_to_create" toEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
widgetEventContent[@"type"] = widgetType;
|
||||
widgetEventContent[@"url"] = widgetUrl;
|
||||
|
||||
if (widgetName)
|
||||
{
|
||||
widgetEventContent[@"name"] = widgetName;
|
||||
}
|
||||
if (widgetData)
|
||||
{
|
||||
widgetEventContent[@"data"] = widgetData;
|
||||
}
|
||||
}
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[room sendStateEventOfType:kWidgetEventTypeString
|
||||
content:widgetEventContent
|
||||
stateKey:widget_id
|
||||
success:^(NSString *eventId) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_failed_to_send_request" toEvent:eventData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getWidgets:(NSDictionary*)eventData
|
||||
{
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
|
||||
if (room)
|
||||
{
|
||||
NSArray<Widget*> *widgets = [[WidgetManager sharedManager] widgetsInRoom:room];
|
||||
|
||||
NSMutableArray<NSDictionary*> *widgetStateEvents = [NSMutableArray arrayWithCapacity:widgets.count];
|
||||
|
||||
for (Widget *widget in widgets)
|
||||
{
|
||||
[widgetStateEvents addObject:widget.widgetEvent.JSONDictionary];
|
||||
}
|
||||
|
||||
[self sendNSObjectResponse:widgetStateEvents toEvent:eventData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)canSendEvent:(NSDictionary*)eventData
|
||||
{
|
||||
NSString *eventType;
|
||||
BOOL isState = NO;
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
|
||||
if (room)
|
||||
{
|
||||
if (room.state.membership != MXMembershipJoin)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_must_be_in_room" toEvent:eventData];
|
||||
return;
|
||||
}
|
||||
|
||||
MXJSONModelSetString(eventType, eventData[@"event_type"]);
|
||||
MXJSONModelSetBoolean(isState, eventData[@"is_state"]);
|
||||
|
||||
MXRoomPowerLevels *powerLevels = room.state.powerLevels;
|
||||
NSInteger userPowerLevel = [powerLevels powerLevelOfUserWithUserID:mxSession.myUser.userId];
|
||||
|
||||
BOOL canSend = NO;
|
||||
|
||||
if (isState)
|
||||
{
|
||||
canSend = (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:eventType]);
|
||||
}
|
||||
else
|
||||
{
|
||||
canSend = (userPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsMessage:eventType]);
|
||||
}
|
||||
|
||||
if (canSend)
|
||||
{
|
||||
[self sendBoolResponse:YES toEvent:eventData];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_no_permission_in_room" toEvent:eventData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getMembershipState:(NSString*)userId eventData:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] membership_state of %@ in room %@ requested.", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
MXRoomMember *member = [room.state memberWithUserId:userId];
|
||||
[self sendNSObjectResponse:member.originalEvent.content toEvent:eventData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getJoinRules:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] join_rules of %@ requested.", roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
MXEvent *event = [room.state stateEventsWithType:kMXEventTypeStringRoomJoinRules].lastObject;
|
||||
[self sendNSObjectResponse:event.JSONDictionary toEvent:eventData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setPlumbingState:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set plumbing state to status %@ in room %@.", eventData[@"status"], roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
NSString *status;
|
||||
MXJSONModelSetString(status, eventData[@"status"]);
|
||||
|
||||
if (status)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[room sendStateEventOfType:kMXEventTypeStringRoomPlumbing
|
||||
content:@{
|
||||
@"status": status
|
||||
}
|
||||
stateKey:nil
|
||||
success:^(NSString *eventId) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_failed_to_send_request" toEvent:eventData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] setPlumbingState. Error: Plumbing state status should be a string.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getBotOptions:(NSString*)userId eventData:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to get options for bot %@ in room %@", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
NSString *stateKey = [NSString stringWithFormat:@"_%@", userId];
|
||||
|
||||
NSArray<MXEvent*> *stateEvents = [room.state stateEventsWithType:kMXEventTypeStringRoomBotOptions];
|
||||
|
||||
MXEvent *botOptionsEvent;
|
||||
|
||||
for (MXEvent *stateEvent in stateEvents)
|
||||
{
|
||||
if ([stateEvent.stateKey isEqualToString:stateKey])
|
||||
{
|
||||
if (!botOptionsEvent || stateEvent.ageLocalTs > botOptionsEvent.ageLocalTs)
|
||||
{
|
||||
botOptionsEvent = stateEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self sendNSObjectResponse:botOptionsEvent.JSONDictionary toEvent:eventData];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBotOptions:(NSString*)userId eventData:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set options for bot %@ in room %@", userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
NSDictionary *content;
|
||||
MXJSONModelSetDictionary(content, eventData[@"content"]);
|
||||
|
||||
if (content)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
NSString *stateKey = [NSString stringWithFormat:@"_%@", userId];
|
||||
|
||||
[room sendStateEventOfType:kMXEventTypeStringRoomBotOptions
|
||||
content:content
|
||||
stateKey:stateKey
|
||||
success:^(NSString *eventId) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
}
|
||||
failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_failed_to_send_request" toEvent:eventData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] setBotOptions. Error: options should be a dict.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBotPower:(NSString*)userId eventData:(NSDictionary*)eventData
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] Received request to set power level to %@ for bot %@ in room %@.", eventData[@"level"], userId, roomId);
|
||||
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
NSInteger level = -1;
|
||||
MXJSONModelSetInteger(level, eventData[@"level"]);
|
||||
|
||||
if (level >= 0)
|
||||
{
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
|
||||
[room setPowerLevelOfUserWithUserID:userId powerLevel:level success:^{
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendNSObjectResponse:@{
|
||||
@"success": @(YES)
|
||||
}
|
||||
toEvent:eventData];
|
||||
}
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
|
||||
typeof(self) self = weakSelf;
|
||||
if (self)
|
||||
{
|
||||
[self sendLocalisedError:@"widget_integration_failed_to_send_request" toEvent:eventData];
|
||||
}
|
||||
}];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"[IntegrationManagerVC] setBotPower. Power level must be positive integer.");
|
||||
[self sendLocalisedError:@"widget_integration_positive_power_level" toEvent:eventData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getMembershipCount:(NSDictionary*)eventData
|
||||
{
|
||||
MXRoom *room = [self roomCheckWithEvent:eventData];
|
||||
if (room)
|
||||
{
|
||||
NSUInteger membershipCount = room.state.joinedMembers.count;
|
||||
[self sendIntegerResponse:membershipCount toEvent:eventData];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "WebViewViewController.h"
|
||||
|
||||
#import "WidgetManager.h"
|
||||
|
||||
/**
|
||||
`WidgetViewController` displays widget within a webview.
|
||||
*/
|
||||
@interface WidgetViewController : WebViewViewController
|
||||
|
||||
/**
|
||||
Init 'WidgetViewController' instance with a widget.
|
||||
|
||||
@param widget the widget to open.
|
||||
*/
|
||||
- (instancetype)initForWidget:(Widget*)widget;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright 2017 Vector Creations Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#import "WidgetViewController.h"
|
||||
|
||||
@interface WidgetViewController ()
|
||||
{
|
||||
Widget *widget;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation WidgetViewController
|
||||
|
||||
- (instancetype)initForWidget:(Widget*)theWidget
|
||||
{
|
||||
self = [super initWithURL:theWidget.url];
|
||||
if (self)
|
||||
{
|
||||
widget = theWidget;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
webView.scalesPageToFit = NO;
|
||||
webView.scrollView.bounces = NO;
|
||||
|
||||
self.navigationItem.title = widget.name;
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user