mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-05-06 07:57:42 +02:00
Merge pull request #2644 from vector-im/riot_2600_2
Prompt to accept integration manager policies on use
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
Changes in 0.9.3 (2019-08-)
|
||||
===============================================
|
||||
|
||||
Improvements:
|
||||
* Prompt to accept integration manager policies on use (#2600).
|
||||
|
||||
Changes in 0.9.2 (2019-08-08)
|
||||
===============================================
|
||||
|
||||
|
||||
@@ -95,6 +95,17 @@
|
||||
32BF995321FA2A1300698084 /* SettingsKeyBackupViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995221FA2A1300698084 /* SettingsKeyBackupViewState.swift */; };
|
||||
32BF995521FA2AB700698084 /* SettingsKeyBackupViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995421FA2AB700698084 /* SettingsKeyBackupViewAction.swift */; };
|
||||
32BF995721FB07A400698084 /* SettingsKeyBackupTableViewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32BF995621FB07A400698084 /* SettingsKeyBackupTableViewSection.swift */; };
|
||||
32DB557522FDADE50016329E /* ServiceTermsModalCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556922FDADE50016329E /* ServiceTermsModalCoordinatorType.swift */; };
|
||||
32DB557622FDADE50016329E /* ServiceTermsModalCoordinatorBridgePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556A22FDADE50016329E /* ServiceTermsModalCoordinatorBridgePresenter.swift */; };
|
||||
32DB557722FDADE50016329E /* ServiceTermsModalCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556B22FDADE50016329E /* ServiceTermsModalCoordinator.swift */; };
|
||||
32DB557822FDADE50016329E /* ServiceTermsModalScreenViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556D22FDADE50016329E /* ServiceTermsModalScreenViewState.swift */; };
|
||||
32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556E22FDADE50016329E /* ServiceTermsModalScreenViewModel.swift */; };
|
||||
32DB557A22FDADE50016329E /* ServiceTermsModalScreenViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB556F22FDADE50016329E /* ServiceTermsModalScreenViewController.swift */; };
|
||||
32DB557B22FDADE50016329E /* ServiceTermsModalScreenViewController.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 32DB557022FDADE50016329E /* ServiceTermsModalScreenViewController.storyboard */; };
|
||||
32DB557C22FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB557122FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift */; };
|
||||
32DB557D22FDADE50016329E /* ServiceTermsModalScreenCoordinatorType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB557222FDADE50016329E /* ServiceTermsModalScreenCoordinatorType.swift */; };
|
||||
32DB557E22FDADE50016329E /* ServiceTermsModalScreenViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB557322FDADE50016329E /* ServiceTermsModalScreenViewAction.swift */; };
|
||||
32DB557F22FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32DB557422FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift */; };
|
||||
32F6B9692270623100BBA352 /* DeviceVerificationDataLoadingCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F6B9632270623000BBA352 /* DeviceVerificationDataLoadingCoordinator.swift */; };
|
||||
32F6B96A2270623100BBA352 /* DeviceVerificationDataLoadingViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F6B9642270623100BBA352 /* DeviceVerificationDataLoadingViewState.swift */; };
|
||||
32F6B96B2270623100BBA352 /* DeviceVerificationDataLoadingViewAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32F6B9652270623100BBA352 /* DeviceVerificationDataLoadingViewAction.swift */; };
|
||||
@@ -701,6 +712,17 @@
|
||||
32D7159E2146CC6F00DF59C9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Vector.strings; sourceTree = "<group>"; };
|
||||
32D7159F2146CC7F00DF59C9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
32D715A02146CC8800DF59C9 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
32DB556922FDADE50016329E /* ServiceTermsModalCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
32DB556A22FDADE50016329E /* ServiceTermsModalCoordinatorBridgePresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalCoordinatorBridgePresenter.swift; sourceTree = "<group>"; };
|
||||
32DB556B22FDADE50016329E /* ServiceTermsModalCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalCoordinator.swift; sourceTree = "<group>"; };
|
||||
32DB556D22FDADE50016329E /* ServiceTermsModalScreenViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenViewState.swift; sourceTree = "<group>"; };
|
||||
32DB556E22FDADE50016329E /* ServiceTermsModalScreenViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenViewModel.swift; sourceTree = "<group>"; };
|
||||
32DB556F22FDADE50016329E /* ServiceTermsModalScreenViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenViewController.swift; sourceTree = "<group>"; };
|
||||
32DB557022FDADE50016329E /* ServiceTermsModalScreenViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = ServiceTermsModalScreenViewController.storyboard; sourceTree = "<group>"; };
|
||||
32DB557122FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenViewModelType.swift; sourceTree = "<group>"; };
|
||||
32DB557222FDADE50016329E /* ServiceTermsModalScreenCoordinatorType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenCoordinatorType.swift; sourceTree = "<group>"; };
|
||||
32DB557322FDADE50016329E /* ServiceTermsModalScreenViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenViewAction.swift; sourceTree = "<group>"; };
|
||||
32DB557422FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ServiceTermsModalScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
32F6B9632270623000BBA352 /* DeviceVerificationDataLoadingCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingCoordinator.swift; sourceTree = "<group>"; };
|
||||
32F6B9642270623100BBA352 /* DeviceVerificationDataLoadingViewState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingViewState.swift; sourceTree = "<group>"; };
|
||||
32F6B9652270623100BBA352 /* DeviceVerificationDataLoadingViewAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceVerificationDataLoadingViewAction.swift; sourceTree = "<group>"; };
|
||||
@@ -1689,6 +1711,40 @@
|
||||
path = KeyBackup;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
32DB556722FDADE50016329E /* ServiceTerms */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
32DB556822FDADE50016329E /* Modal */,
|
||||
);
|
||||
path = ServiceTerms;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
32DB556822FDADE50016329E /* Modal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
32DB556922FDADE50016329E /* ServiceTermsModalCoordinatorType.swift */,
|
||||
32DB556A22FDADE50016329E /* ServiceTermsModalCoordinatorBridgePresenter.swift */,
|
||||
32DB556B22FDADE50016329E /* ServiceTermsModalCoordinator.swift */,
|
||||
32DB556C22FDADE50016329E /* Modal */,
|
||||
);
|
||||
path = Modal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
32DB556C22FDADE50016329E /* Modal */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
32DB556D22FDADE50016329E /* ServiceTermsModalScreenViewState.swift */,
|
||||
32DB556E22FDADE50016329E /* ServiceTermsModalScreenViewModel.swift */,
|
||||
32DB556F22FDADE50016329E /* ServiceTermsModalScreenViewController.swift */,
|
||||
32DB557022FDADE50016329E /* ServiceTermsModalScreenViewController.storyboard */,
|
||||
32DB557122FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift */,
|
||||
32DB557222FDADE50016329E /* ServiceTermsModalScreenCoordinatorType.swift */,
|
||||
32DB557322FDADE50016329E /* ServiceTermsModalScreenViewAction.swift */,
|
||||
32DB557422FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift */,
|
||||
);
|
||||
path = Modal;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
4220F60B660591FD80AF3428 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2178,6 +2234,7 @@
|
||||
B1B5567620EE6C4C00210D55 /* Modules */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
32DB556722FDADE50016329E /* ServiceTerms */,
|
||||
3232AB94225730E100AD6A5C /* DeviceVerification */,
|
||||
B1B556EA20EE6C4C00210D55 /* Main */,
|
||||
B1B556CA20EE6C4C00210D55 /* TabBar */,
|
||||
@@ -3833,6 +3890,7 @@
|
||||
B1B5574D20EE6C4D00210D55 /* MediaPickerViewController.xib in Resources */,
|
||||
B1B5575020EE6C4D00210D55 /* AuthenticationViewController.xib in Resources */,
|
||||
B14F142E22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewController.storyboard in Resources */,
|
||||
32DB557B22FDADE50016329E /* ServiceTermsModalScreenViewController.storyboard in Resources */,
|
||||
B1B5574320EE6C4D00210D55 /* CallViewController.xib in Resources */,
|
||||
F083BDEA1E7009ED00A9B29C /* ringback.mp3 in Resources */,
|
||||
F083BDF21E7009ED00A9B29C /* GoogleService-Info.plist in Resources */,
|
||||
@@ -4152,6 +4210,7 @@
|
||||
B19EFA3B21F8BB4100FC070E /* KeyBackupRecoverCoordinator.swift in Sources */,
|
||||
B1B9DEDE22E9D9890065E677 /* EmojiServiceType.swift in Sources */,
|
||||
3232ABA9225730E100AD6A5C /* DeviceVerificationStartViewModel.swift in Sources */,
|
||||
32DB557C22FDADE50016329E /* ServiceTermsModalScreenViewModelType.swift in Sources */,
|
||||
B16932FA20F3C51A00746532 /* RecentCellData.m in Sources */,
|
||||
B16932F220F3C49E00746532 /* GroupsDataSource.m in Sources */,
|
||||
B1B5581C20EF625800210D55 /* RoomAvatarTitleView.m in Sources */,
|
||||
@@ -4227,6 +4286,7 @@
|
||||
B169331420F3CAFC00746532 /* PublicRoomTableViewCell.m in Sources */,
|
||||
32BF995721FB07A400698084 /* SettingsKeyBackupTableViewSection.swift in Sources */,
|
||||
B14F142F22144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewModelType.swift in Sources */,
|
||||
32DB557822FDADE50016329E /* ServiceTermsModalScreenViewState.swift in Sources */,
|
||||
B1B558E120EF768F00210D55 /* RoomMembershipCollapsedBubbleCell.m in Sources */,
|
||||
B1B5571A20EE6C4D00210D55 /* SettingsViewController.m in Sources */,
|
||||
B1CE9EFD22148703000FAE6A /* SignOutAlertPresenter.swift in Sources */,
|
||||
@@ -4247,6 +4307,7 @@
|
||||
3275FD8C21A5A2C500B9C13D /* TermsView.swift in Sources */,
|
||||
B1B9DEE822EB34EF0065E677 /* ReactionHistoryCoordinatorType.swift in Sources */,
|
||||
B14F143122144F6500FA0595 /* KeyBackupRecoverFromRecoveryKeyViewState.swift in Sources */,
|
||||
32DB557F22FDADE50016329E /* ServiceTermsModalScreenCoordinator.swift in Sources */,
|
||||
B1098C1121ED07E4000DDA48 /* NavigationRouterType.swift in Sources */,
|
||||
B1B5573D20EE6C4D00210D55 /* WebViewViewController.m in Sources */,
|
||||
3209451221F1C1430088CAA2 /* BlackTheme.swift in Sources */,
|
||||
@@ -4254,6 +4315,8 @@
|
||||
3232ABBC2257BE6500AD6A5C /* DeviceVerificationVerifyViewAction.swift in Sources */,
|
||||
F05927C91FDED836009F2A68 /* MXGroup+Riot.m in Sources */,
|
||||
B1B5594520EF7BD000210D55 /* TableViewCellWithCollectionView.m in Sources */,
|
||||
32DB557722FDADE50016329E /* ServiceTermsModalCoordinator.swift in Sources */,
|
||||
32DB557922FDADE50016329E /* ServiceTermsModalScreenViewModel.swift in Sources */,
|
||||
32891D75226728EE00C82226 /* DeviceVerificationDataLoadingViewController.swift in Sources */,
|
||||
32891D712264DF7B00C82226 /* DeviceVerificationVerifiedViewController.swift in Sources */,
|
||||
F083BDEF1E7009ED00A9B29C /* UINavigationController+Riot.m in Sources */,
|
||||
@@ -4264,6 +4327,7 @@
|
||||
B1B5571920EE6C4D00210D55 /* LanguagePickerViewController.m in Sources */,
|
||||
3232AB512256558300AD6A5C /* TemplateScreenViewAction.swift in Sources */,
|
||||
3232AB4E2256558300AD6A5C /* TemplateScreenViewModelType.swift in Sources */,
|
||||
32DB557D22FDADE50016329E /* ServiceTermsModalScreenCoordinatorType.swift in Sources */,
|
||||
B1B5590520EF768F00210D55 /* RoomIncomingTextMsgWithoutSenderInfoBubbleCell.m in Sources */,
|
||||
3232ABA5225730E100AD6A5C /* DeviceVerificationStartViewModelType.swift in Sources */,
|
||||
B1B558DD20EF768F00210D55 /* RoomIncomingEncryptedTextMsgBubbleCell.m in Sources */,
|
||||
@@ -4274,6 +4338,7 @@
|
||||
B1D4752721EE4E630067973F /* KeyboardAvoider.swift in Sources */,
|
||||
B1D4752821EE4E630067973F /* KeyboardNotification.swift in Sources */,
|
||||
B1D1BDA622BBAFB500831367 /* ReactionsMenuView.swift in Sources */,
|
||||
32DB557A22FDADE50016329E /* ServiceTermsModalScreenViewController.swift in Sources */,
|
||||
B1B9DEF422EB426D0065E677 /* ReactionHistoryViewCell.swift in Sources */,
|
||||
B1B5573C20EE6C4D00210D55 /* MasterTabBarController.m in Sources */,
|
||||
B1DCC61B22E5E17100625807 /* EmojiPickerCoordinator.swift in Sources */,
|
||||
@@ -4447,6 +4512,7 @@
|
||||
B1B557CC20EF5D8000210D55 /* DirectoryServerTableViewCell.m in Sources */,
|
||||
B1963B2B228F1C4900CBA17F /* BubbleReactionsView.swift in Sources */,
|
||||
B1B5575C20EE6C4D00210D55 /* DirectoryViewController.m in Sources */,
|
||||
32DB557622FDADE50016329E /* ServiceTermsModalCoordinatorBridgePresenter.swift in Sources */,
|
||||
B1B558BD20EF768F00210D55 /* RoomOutgoingEncryptedTextMsgWithoutSenderNameBubbleCell.m in Sources */,
|
||||
B1B5577020EE702800210D55 /* WidgetPickerViewController.m in Sources */,
|
||||
B1B558D320EF768F00210D55 /* RoomOutgoingEncryptedTextMsgBubbleCell.m in Sources */,
|
||||
@@ -4462,6 +4528,7 @@
|
||||
32B94DF9228EC26400716A26 /* ReactionsMenuViewAction.swift in Sources */,
|
||||
B1B5599420EFC5E400210D55 /* DecryptionFailureTracker.m in Sources */,
|
||||
F083BDF01E7009ED00A9B29C /* UIViewController+RiotSearch.m in Sources */,
|
||||
32DB557522FDADE50016329E /* ServiceTermsModalCoordinatorType.swift in Sources */,
|
||||
F083BDF91E7009ED00A9B29C /* RoomEmailInvitation.m in Sources */,
|
||||
B1D211E422C18E3800D939BD /* ReactionsMenuViewModelType.swift in Sources */,
|
||||
324A2055225FC571004FE8B0 /* DeviceVerificationIncomingViewModelType.swift in Sources */,
|
||||
@@ -4470,6 +4537,7 @@
|
||||
3232ABB52257BE6400AD6A5C /* DeviceVerificationVerifyCoordinatorType.swift in Sources */,
|
||||
32BF994F21FA29A400698084 /* SettingsKeyBackupViewModel.swift in Sources */,
|
||||
B190F55D22CE5A9700AEB493 /* EditHistorySection.swift in Sources */,
|
||||
32DB557E22FDADE50016329E /* ServiceTermsModalScreenViewAction.swift in Sources */,
|
||||
32A6002022C66FCF0042C1D9 /* EditHistoryMessage.swift in Sources */,
|
||||
B1B5574920EE6C4D00210D55 /* RiotSplitViewController.m in Sources */,
|
||||
B1B5574E20EE6C4D00210D55 /* DirectoryServerPickerViewController.m in Sources */,
|
||||
|
||||
@@ -691,6 +691,13 @@
|
||||
"gdpr_consent_not_given_alert_message" = "To continue using the %@ homeserver you must review and agree to the terms and conditions.";
|
||||
"gdpr_consent_not_given_alert_review_now_action" = "Review now";
|
||||
|
||||
// Service terms
|
||||
"service_terms_modal_title" = "Terms Of Service";
|
||||
"service_terms_modal_message" = "To continue you need to accept the Terms of this service.";
|
||||
"service_terms_modal_accept_button" = "Accept";
|
||||
"service_terms_modal_description_for_identity_server" = "Be discoverable by others";
|
||||
"service_terms_modal_description_for_integration_manager" = "Use Bots, bridges, widgets and sticker packs";
|
||||
|
||||
// Deactivate account
|
||||
|
||||
"deactivate_account_title" = "Deactivate Account";
|
||||
|
||||
@@ -92,6 +92,11 @@ internal enum StoryboardScene {
|
||||
|
||||
internal static let initialScene = InitialSceneType<Riot.RoomContextualMenuViewController>(storyboard: RoomContextualMenuViewController.self)
|
||||
}
|
||||
internal enum ServiceTermsModalScreenViewController: StoryboardType {
|
||||
internal static let storyboardName = "ServiceTermsModalScreenViewController"
|
||||
|
||||
internal static let initialScene = InitialSceneType<Riot.ServiceTermsModalScreenViewController>(storyboard: ServiceTermsModalScreenViewController.self)
|
||||
}
|
||||
internal enum SimpleScreenTemplateViewController: StoryboardType {
|
||||
internal static let storyboardName = "SimpleScreenTemplateViewController"
|
||||
|
||||
|
||||
@@ -2342,6 +2342,26 @@ internal enum VectorL10n {
|
||||
internal static var sending: String {
|
||||
return VectorL10n.tr("Vector", "sending")
|
||||
}
|
||||
/// Accept
|
||||
internal static var serviceTermsModalAcceptButton: String {
|
||||
return VectorL10n.tr("Vector", "service_terms_modal_accept_button")
|
||||
}
|
||||
/// Be discoverable by others
|
||||
internal static var serviceTermsModalDescriptionForIdentityServer: String {
|
||||
return VectorL10n.tr("Vector", "service_terms_modal_description_for_identity_server")
|
||||
}
|
||||
/// Use Bots, bridges, widgets and sticker packs
|
||||
internal static var serviceTermsModalDescriptionForIntegrationManager: String {
|
||||
return VectorL10n.tr("Vector", "service_terms_modal_description_for_integration_manager")
|
||||
}
|
||||
/// To continue you need to accept the Terms of this service.
|
||||
internal static var serviceTermsModalMessage: String {
|
||||
return VectorL10n.tr("Vector", "service_terms_modal_message")
|
||||
}
|
||||
/// Terms Of Service
|
||||
internal static var serviceTermsModalTitle: String {
|
||||
return VectorL10n.tr("Vector", "service_terms_modal_title")
|
||||
}
|
||||
/// Add email address
|
||||
internal static var settingsAddEmailAddress: String {
|
||||
return VectorL10n.tr("Vector", "settings_add_email_address")
|
||||
|
||||
@@ -56,10 +56,12 @@ typedef enum : NSUInteger
|
||||
WidgetManagerErrorCodeNotEnoughPower,
|
||||
WidgetManagerErrorCodeCreationFailed,
|
||||
WidgetManagerErrorCodeNoIntegrationsServerConfigured,
|
||||
WidgetManagerErrorCodeFailedToConnectToIntegrationsServer
|
||||
WidgetManagerErrorCodeFailedToConnectToIntegrationsServer,
|
||||
WidgetManagerErrorCodeTermsNotSigned
|
||||
}
|
||||
WidgetManagerErrorCode;
|
||||
|
||||
FOUNDATION_EXPORT NSString *const WidgetManagerErrorOpenIdTokenKey;
|
||||
|
||||
/**
|
||||
The `WidgetManager` helps to handle modular widgets.
|
||||
|
||||
@@ -513,6 +513,8 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
MXHTTPOperation *operation;
|
||||
NSString *userId = mxSession.myUser.userId;
|
||||
|
||||
NSLog(@"[WidgetManager] registerForScalarToken");
|
||||
|
||||
WidgetManagerConfig *config = [self configForUser:userId];
|
||||
if (!config.hasUrls)
|
||||
{
|
||||
@@ -537,15 +539,22 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
|
||||
NSString *scalarToken;
|
||||
MXJSONModelSetString(scalarToken, JSONResponse[@"scalar_token"])
|
||||
config.scalarToken = scalarToken;
|
||||
|
||||
config.scalarToken = scalarToken;
|
||||
self->configs[userId] = config;
|
||||
[self saveConfigs];
|
||||
|
||||
// Validate it (this mostly checks to see if the IM needs us to agree to some terms)
|
||||
MXHTTPOperation *operation3 = [self validateScalarToken:scalarToken forMXSession:mxSession complete:^(BOOL valid) {
|
||||
|
||||
if (success)
|
||||
{
|
||||
success(scalarToken);
|
||||
}
|
||||
if (success)
|
||||
{
|
||||
success(scalarToken);
|
||||
}
|
||||
|
||||
} failure:failure];
|
||||
|
||||
[operation mutateTo:operation3];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[WidgetManager] registerForScalarToken: Failed to register. Error: %@", error);
|
||||
@@ -622,7 +631,22 @@ NSString *const WidgetManagerErrorDomain = @"WidgetManagerErrorDomain";
|
||||
}
|
||||
else if (failure)
|
||||
{
|
||||
failure(error);
|
||||
MXError *mxError = [[MXError alloc] initWithNSError:error];
|
||||
if ([mxError.errcode isEqualToString:kMXErrCodeStringTermsNotSigned])
|
||||
{
|
||||
NSLog(@"[WidgetManager] validateScalarToke. Error: Need to accept terms");
|
||||
NSError *termsNotSignedError = [NSError errorWithDomain:WidgetManagerErrorDomain
|
||||
code:WidgetManagerErrorCodeTermsNotSigned
|
||||
userInfo:@{
|
||||
NSLocalizedDescriptionKey:error.userInfo[NSLocalizedDescriptionKey]
|
||||
}];
|
||||
|
||||
failure(termsNotSignedError);
|
||||
}
|
||||
else
|
||||
{
|
||||
failure(error);
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -36,6 +36,38 @@ class WidgetManagerConfig: NSObject, NSCoding {
|
||||
}
|
||||
}
|
||||
|
||||
var baseUrl: NSString? {
|
||||
// Same comment as https://github.com/matrix-org/matrix-react-sdk/blob/1b0d8510a2ee93beddcd34c2d5770aa9fc76b1d9/src/ScalarAuthClient.js#L108
|
||||
// The terms endpoints are new and so live on standard _matrix prefixes,
|
||||
// but IM rest urls are currently configured with paths, so remove the
|
||||
// path from the base URL before passing it to the js-sdk
|
||||
|
||||
// We continue to use the full URL for the calls done by
|
||||
// Riot-iOS, but the standard terms API called
|
||||
// by the matrix-ios-sdk lives on the standard _matrix path. This means we
|
||||
// don't support running IMs on a non-root path, but it's the only
|
||||
// realistic way of transitioning to _matrix paths since configs in
|
||||
// the wild contain bits of the API path.
|
||||
|
||||
// Once we've fully transitioned to _matrix URLs, we can give people
|
||||
// a grace period to update their configs, then use the rest url as
|
||||
// a regular base url.
|
||||
guard let apiUrl = self.apiUrl as String?, let imApiUrl = URL(string: apiUrl) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard var baseUrl = URL(string: "/", relativeTo: imApiUrl)?.absoluteString else {
|
||||
return nil
|
||||
}
|
||||
|
||||
if baseUrl.hasSuffix("/") {
|
||||
// SDK doest not like trailing /
|
||||
baseUrl = String(baseUrl.dropLast())
|
||||
}
|
||||
|
||||
return baseUrl as NSString
|
||||
}
|
||||
|
||||
init(apiUrl: NSString?, uiUrl: NSString?) {
|
||||
self.apiUrl = apiUrl
|
||||
self.uiUrl = uiUrl
|
||||
|
||||
@@ -26,7 +26,7 @@ NSString *const kIntegrationManagerMainScreen = nil;
|
||||
NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
|
||||
|
||||
@interface IntegrationManagerViewController ()
|
||||
@interface IntegrationManagerViewController () <ServiceTermsModalCoordinatorBridgePresenterDelegate>
|
||||
{
|
||||
MXSession *mxSession;
|
||||
NSString *roomId;
|
||||
@@ -37,6 +37,8 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
MXHTTPOperation *operation;
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;
|
||||
|
||||
@end
|
||||
|
||||
@implementation IntegrationManagerViewController
|
||||
@@ -67,10 +69,15 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
operation = nil;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
[super viewDidLoad];
|
||||
|
||||
[self loadData];
|
||||
}
|
||||
|
||||
- (void)loadData
|
||||
{
|
||||
if (!self.URL && !operation)
|
||||
{
|
||||
[self startActivityIndicator];
|
||||
@@ -94,9 +101,17 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
self->operation = nil;
|
||||
[self stopActivityIndicator];
|
||||
|
||||
[self withdrawViewControllerAnimated:YES completion:^{
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
if ([error.domain isEqualToString:WidgetManagerErrorDomain]
|
||||
&& error.code == WidgetManagerErrorCodeTermsNotSigned)
|
||||
{
|
||||
[self presentTerms];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self withdrawViewControllerAnimated:YES completion:^{
|
||||
[[AppDelegate theDelegate] showErrorAsAlert:error];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -681,4 +696,39 @@ NSString *const kIntegrationManagerAddIntegrationScreen = @"add_integ";
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Service terms
|
||||
|
||||
- (void)presentTerms
|
||||
{
|
||||
WidgetManagerConfig *config = [[WidgetManager sharedManager] configForUser:mxSession.myUser.userId];
|
||||
|
||||
NSLog(@"[IntegrationManagerVC] presentTerms for %@", config.baseUrl);
|
||||
|
||||
ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter = [[ServiceTermsModalCoordinatorBridgePresenter alloc] initWithSession: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
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self loadData];
|
||||
}];
|
||||
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
- (void)serviceTermsModalCoordinatorBridgePresenterDelegateDidCancel:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self withdrawViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -19,10 +19,13 @@
|
||||
|
||||
#import "AppDelegate.h"
|
||||
#import "IntegrationManagerViewController.h"
|
||||
#import "Riot-Swift.h"
|
||||
|
||||
NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse('%@', %@);";
|
||||
|
||||
@interface WidgetViewController ()
|
||||
@interface WidgetViewController () <ServiceTermsModalCoordinatorBridgePresenterDelegate>
|
||||
|
||||
@property (nonatomic, strong) ServiceTermsModalCoordinatorBridgePresenter *serviceTermsModalCoordinatorBridgePresenter;
|
||||
|
||||
@end
|
||||
|
||||
@@ -363,15 +366,71 @@ NSString *const kJavascriptSendResponseToPostMessageAPI = @"riotIOS.sendResponse
|
||||
MXStrongifyAndReturnIfNil(self);
|
||||
|
||||
NSLog(@"[WidgetVC] fixScalarToken: DONE");
|
||||
|
||||
self.URL = [self stringByReplacingScalarTokenInString:self.URL byScalarToken:scalarToken];
|
||||
|
||||
self->webView.hidden = NO;
|
||||
[self loadDataWithScalarToken:scalarToken];
|
||||
|
||||
} failure:^(NSError *error) {
|
||||
NSLog(@"[WidgetVC] fixScalarToken: Error: %@", error);
|
||||
[self showErrorAsAlert: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];
|
||||
|
||||
NSLog(@"[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)serviceTermsModalCoordinatorBridgePresenterDelegateDidCancel:(ServiceTermsModalCoordinatorBridgePresenter * _Nonnull)coordinatorBridgePresenter
|
||||
{
|
||||
[coordinatorBridgePresenter dismissWithAnimated:YES completion:^{
|
||||
[self withdrawViewControllerAnimated:YES completion:nil];
|
||||
}];
|
||||
self.serviceTermsModalCoordinatorBridgePresenter = nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
import UIKit
|
||||
|
||||
final class ServiceTermsModalScreenCoordinator: ServiceTermsModalScreenCoordinatorType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var serviceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelType
|
||||
private let serviceTermsModalScreenViewController: ServiceTermsModalScreenViewController
|
||||
|
||||
// Must be used only internally
|
||||
var childCoordinators: [Coordinator] = []
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: ServiceTermsModalScreenCoordinatorDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(serviceTerms: MXServiceTerms) {
|
||||
|
||||
let serviceTermsModalScreenViewModel = ServiceTermsModalScreenViewModel(serviceTerms: serviceTerms)
|
||||
let serviceTermsModalScreenViewController = ServiceTermsModalScreenViewController.instantiate(with: serviceTermsModalScreenViewModel)
|
||||
self.serviceTermsModalScreenViewModel = serviceTermsModalScreenViewModel
|
||||
self.serviceTermsModalScreenViewController = serviceTermsModalScreenViewController
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
self.serviceTermsModalScreenViewModel.coordinatorDelegate = self
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.serviceTermsModalScreenViewController
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ServiceTermsModalScreenViewModelCoordinatorDelegate
|
||||
extension ServiceTermsModalScreenCoordinator: ServiceTermsModalScreenViewModelCoordinatorDelegate {
|
||||
|
||||
func serviceTermsModalScreenViewModelDidAccept(_ viewModel: ServiceTermsModalScreenViewModelType) {
|
||||
self.delegate?.serviceTermsModalScreenCoordinatorDidAccept(self)
|
||||
}
|
||||
|
||||
func serviceTermsModalScreenViewModel(_ coordinator: ServiceTermsModalScreenViewModelType, displayPolicy policy: MXLoginPolicyData) {
|
||||
self.delegate?.serviceTermsModalScreenCoordinator(self, displayPolicy: policy)
|
||||
}
|
||||
|
||||
func serviceTermsModalScreenViewModelDidCancel(_ viewModel: ServiceTermsModalScreenViewModelType) {
|
||||
self.delegate?.serviceTermsModalScreenCoordinatorDidCancel(self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
protocol ServiceTermsModalScreenCoordinatorDelegate: class {
|
||||
func serviceTermsModalScreenCoordinatorDidAccept(_ coordinator: ServiceTermsModalScreenCoordinatorType)
|
||||
func serviceTermsModalScreenCoordinator(_ coordinator: ServiceTermsModalScreenCoordinatorType, displayPolicy policy: MXLoginPolicyData)
|
||||
func serviceTermsModalScreenCoordinatorDidCancel(_ coordinator: ServiceTermsModalScreenCoordinatorType)
|
||||
}
|
||||
|
||||
/// `ServiceTermsModalScreenCoordinatorType` is a protocol describing a Coordinator that handle key backup setup passphrase navigation flow.
|
||||
protocol ServiceTermsModalScreenCoordinatorType: Coordinator, Presentable {
|
||||
var delegate: ServiceTermsModalScreenCoordinatorDelegate? { get }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
/// ServiceTermsModalScreenViewController view actions exposed to view model
|
||||
enum ServiceTermsModalScreenViewAction {
|
||||
case load
|
||||
case display(MXLoginPolicyData)
|
||||
case accept
|
||||
case cancel
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="V8j-Lb-PgC">
|
||||
<device id="retina6_1" orientation="portrait">
|
||||
<adaptation id="fullscreen"/>
|
||||
</device>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Service Terms Modal Screen View Controller-->
|
||||
<scene sceneID="mt5-wz-YKA">
|
||||
<objects>
|
||||
<viewController extendedLayoutIncludesOpaqueBars="YES" automaticallyAdjustsScrollViewInsets="NO" id="V8j-Lb-PgC" customClass="ServiceTermsModalScreenViewController" customModule="Riot" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="EL9-GA-lwo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="9U2-KL-ZVA">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="852"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e7g-um-WO4">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="852"/>
|
||||
<subviews>
|
||||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="voD-3Q-ryt">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="852"/>
|
||||
<subviews>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="To continue you need to accept the Terms of this service." textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bxI-mu-qng">
|
||||
<rect key="frame" x="20" y="20" width="374" height="100"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="100" id="1bP-8m-xrd"/>
|
||||
</constraints>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/>
|
||||
<nil key="textColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="swq-xw-ItG">
|
||||
<rect key="frame" x="20" y="128" width="374" height="652"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="DOt-5E-FjF">
|
||||
<rect key="frame" x="20" y="788" width="374" height="44"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="44" id="d2a-Dw-Pu5"/>
|
||||
</constraints>
|
||||
<state key="normal" title="Accept"/>
|
||||
<connections>
|
||||
<action selector="acceptButtonAction:" destination="V8j-Lb-PgC" eventType="touchUpInside" id="uvI-tt-Nfj"/>
|
||||
</connections>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="1K2-u8-QsL"/>
|
||||
<constraint firstAttribute="bottom" secondItem="DOt-5E-FjF" secondAttribute="bottom" constant="20" symbolic="YES" id="2Vt-c1-fPz"/>
|
||||
<constraint firstAttribute="trailing" secondItem="bxI-mu-qng" secondAttribute="trailing" constant="20" symbolic="YES" id="41D-TP-69f"/>
|
||||
<constraint firstItem="DOt-5E-FjF" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="43V-Ya-vks"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="top" secondItem="bxI-mu-qng" secondAttribute="bottom" constant="8" symbolic="YES" id="9Gg-Xb-o2W"/>
|
||||
<constraint firstItem="DOt-5E-FjF" firstAttribute="top" secondItem="swq-xw-ItG" secondAttribute="bottom" constant="8" symbolic="YES" id="K8z-wm-8yT"/>
|
||||
<constraint firstItem="bxI-mu-qng" firstAttribute="top" secondItem="voD-3Q-ryt" secondAttribute="top" constant="20" symbolic="YES" id="W1m-x0-TyS"/>
|
||||
<constraint firstAttribute="trailing" secondItem="swq-xw-ItG" secondAttribute="trailing" constant="20" symbolic="YES" id="Y5v-Gg-xkM"/>
|
||||
<constraint firstAttribute="width" priority="750" constant="500" id="glD-Sz-73O"/>
|
||||
<constraint firstAttribute="trailing" secondItem="DOt-5E-FjF" secondAttribute="trailing" constant="20" symbolic="YES" id="lpw-9u-VDG"/>
|
||||
<constraint firstItem="swq-xw-ItG" firstAttribute="leading" secondItem="voD-3Q-ryt" secondAttribute="leading" constant="20" symbolic="YES" id="ze1-Iw-v9U"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="voD-3Q-ryt" secondAttribute="bottom" id="63a-5e-ptU"/>
|
||||
<constraint firstItem="voD-3Q-ryt" firstAttribute="centerX" secondItem="e7g-um-WO4" secondAttribute="centerX" id="P2G-mq-gQW"/>
|
||||
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="voD-3Q-ryt" secondAttribute="trailing" id="QgV-SO-5yf"/>
|
||||
<constraint firstItem="voD-3Q-ryt" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e7g-um-WO4" secondAttribute="leading" id="YPo-u1-PtT"/>
|
||||
<constraint firstItem="voD-3Q-ryt" firstAttribute="top" secondItem="e7g-um-WO4" secondAttribute="top" id="rhQ-96-szL"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="e7g-um-WO4" firstAttribute="height" secondItem="9U2-KL-ZVA" secondAttribute="height" priority="500" id="GP8-i4-Fqh"/>
|
||||
<constraint firstAttribute="trailing" secondItem="e7g-um-WO4" secondAttribute="trailing" id="GyG-Fh-PME"/>
|
||||
<constraint firstItem="e7g-um-WO4" firstAttribute="width" secondItem="9U2-KL-ZVA" secondAttribute="width" id="Ok2-WQ-Zgc"/>
|
||||
<constraint firstAttribute="bottom" secondItem="e7g-um-WO4" secondAttribute="bottom" id="Y46-NP-zAc"/>
|
||||
<constraint firstItem="e7g-um-WO4" firstAttribute="leading" secondItem="9U2-KL-ZVA" secondAttribute="leading" id="aoV-Yh-AcD"/>
|
||||
<constraint firstItem="e7g-um-WO4" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="pFN-bA-SHw"/>
|
||||
</constraints>
|
||||
</scrollView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" red="0.94509803921568625" green="0.96078431372549022" blue="0.97254901960784312" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="bottom" secondItem="9U2-KL-ZVA" secondAttribute="bottom" id="7Cb-nY-CsO"/>
|
||||
<constraint firstItem="9U2-KL-ZVA" firstAttribute="leading" secondItem="bFg-jh-JZB" secondAttribute="leading" id="GdQ-hK-muG"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="trailing" secondItem="9U2-KL-ZVA" secondAttribute="trailing" id="sbD-ek-vGJ"/>
|
||||
<constraint firstItem="bFg-jh-JZB" firstAttribute="top" secondItem="9U2-KL-ZVA" secondAttribute="top" id="wTB-V6-IHV"/>
|
||||
</constraints>
|
||||
<viewLayoutGuide key="safeArea" id="bFg-jh-JZB"/>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="acceptButton" destination="DOt-5E-FjF" id="ktw-U4-efQ"/>
|
||||
<outlet property="messageLabel" destination="bxI-mu-qng" id="pbX-aZ-inC"/>
|
||||
<outlet property="scrollView" destination="9U2-KL-ZVA" id="ojG-2y-X7b"/>
|
||||
<outlet property="tableView" destination="swq-xw-ItG" id="Fwb-Sc-bec"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="zK0-v6-7Wt" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-3198" y="-647"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -0,0 +1,293 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 UIKit
|
||||
|
||||
final class ServiceTermsModalScreenViewController: UIViewController {
|
||||
|
||||
// MARK: - Constants
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Outlets
|
||||
|
||||
@IBOutlet private weak var scrollView: UIScrollView!
|
||||
|
||||
@IBOutlet private weak var messageLabel: UILabel!
|
||||
@IBOutlet private weak var tableView: UITableView!
|
||||
@IBOutlet private weak var acceptButton: UIButton!
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var viewModel: ServiceTermsModalScreenViewModelType!
|
||||
private var theme: Theme!
|
||||
private var errorPresenter: MXKErrorPresentation!
|
||||
private var activityPresenter: ActivityIndicatorPresenter!
|
||||
|
||||
private var policies: [MXLoginPolicyData] = []
|
||||
|
||||
/// Policies checked by the end user
|
||||
private var checkedPolicies: Set<Int> = []
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
class func instantiate(with viewModel: ServiceTermsModalScreenViewModelType) -> ServiceTermsModalScreenViewController {
|
||||
let viewController = StoryboardScene.ServiceTermsModalScreenViewController.initialScene.instantiate()
|
||||
viewController.viewModel = viewModel
|
||||
viewController.theme = ThemeService.shared().theme
|
||||
return viewController
|
||||
}
|
||||
|
||||
// MARK: - Life cycle
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Do any additional setup after loading the view.
|
||||
|
||||
self.title = VectorL10n.serviceTermsModalTitle
|
||||
|
||||
self.setupViews()
|
||||
self.activityPresenter = ActivityIndicatorPresenter()
|
||||
self.errorPresenter = MXKErrorAlertPresentation()
|
||||
|
||||
self.registerThemeServiceDidChangeThemeNotification()
|
||||
self.update(theme: self.theme)
|
||||
|
||||
self.viewModel.viewDelegate = self
|
||||
|
||||
self.viewModel.process(viewAction: .load)
|
||||
}
|
||||
|
||||
override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
return self.theme.statusBarStyle
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func update(theme: Theme) {
|
||||
self.theme = theme
|
||||
|
||||
self.view.backgroundColor = theme.headerBackgroundColor
|
||||
|
||||
if let navigationBar = self.navigationController?.navigationBar {
|
||||
theme.applyStyle(onNavigationBar: navigationBar)
|
||||
}
|
||||
|
||||
self.messageLabel.textColor = theme.textPrimaryColor
|
||||
|
||||
self.acceptButton.backgroundColor = theme.backgroundColor
|
||||
theme.applyStyle(onButton: self.acceptButton)
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
|
||||
private func registerThemeServiceDidChangeThemeNotification() {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(themeDidChange), name: .themeServiceDidChangeTheme, object: nil)
|
||||
}
|
||||
|
||||
@objc private func themeDidChange() {
|
||||
self.update(theme: ThemeService.shared().theme)
|
||||
}
|
||||
|
||||
private func setupViews() {
|
||||
let cancelBarButtonItem = MXKBarButtonItem(title: VectorL10n.cancel, style: .plain) { [weak self] in
|
||||
self?.cancelButtonAction()
|
||||
}
|
||||
|
||||
self.navigationItem.rightBarButtonItem = cancelBarButtonItem
|
||||
|
||||
self.setupTableView()
|
||||
self.scrollView.keyboardDismissMode = .interactive
|
||||
|
||||
self.messageLabel.text = VectorL10n.serviceTermsModalMessage
|
||||
|
||||
self.acceptButton.setTitle(VectorL10n.serviceTermsModalAcceptButton, for: .normal)
|
||||
self.acceptButton.setTitle(VectorL10n.serviceTermsModalAcceptButton, for: .highlighted)
|
||||
self.refreshAcceptButton()
|
||||
}
|
||||
|
||||
private func setupTableView() {
|
||||
self.tableView.delegate = self
|
||||
self.tableView.dataSource = self
|
||||
self.tableView.separatorStyle = .none
|
||||
self.tableView.alwaysBounceVertical = false
|
||||
self.tableView.backgroundColor = .clear
|
||||
self.tableView.register(TableViewCellWithCheckBoxAndLabel.nib(), forCellReuseIdentifier: TableViewCellWithCheckBoxAndLabel.defaultReuseIdentifier())
|
||||
}
|
||||
|
||||
private func render(viewState: ServiceTermsModalScreenViewState) {
|
||||
switch viewState {
|
||||
case .loading:
|
||||
self.renderLoading()
|
||||
case .loaded(let policies, let alreadyAcceptedPoliciesUrls):
|
||||
self.renderLoaded(policies: policies, alreadyAcceptedPoliciesUrls: alreadyAcceptedPoliciesUrls)
|
||||
case .accepted:
|
||||
self.renderAccepted()
|
||||
case .error(let error):
|
||||
self.render(error: error)
|
||||
}
|
||||
}
|
||||
|
||||
private func renderLoading() {
|
||||
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
|
||||
}
|
||||
|
||||
private func renderLoaded(policies: [MXLoginPolicyData], alreadyAcceptedPoliciesUrls: [String]) {
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
|
||||
self.policies = policies
|
||||
self.updateCheckedPolicies(with: alreadyAcceptedPoliciesUrls)
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
|
||||
private func renderAccepting() {
|
||||
self.activityPresenter.presentActivityIndicator(on: self.view, animated: true)
|
||||
}
|
||||
|
||||
private func renderAccepted() {
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
}
|
||||
|
||||
private func render(error: Error) {
|
||||
self.activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
self.errorPresenter.presentError(from: self, forError: error, animated: true, handler: nil)
|
||||
}
|
||||
|
||||
private func refreshViews() {
|
||||
self.tableView.reloadData()
|
||||
self.refreshAcceptButton()
|
||||
}
|
||||
|
||||
private func refreshAcceptButton() {
|
||||
// Enable the button only if the user has accepted all policies
|
||||
self.acceptButton.isEnabled = (self.policies.count == self.checkedPolicies.count)
|
||||
}
|
||||
|
||||
// Pre-check policies already accepted by the user
|
||||
private func updateCheckedPolicies(with acceptedPoliciesUrls: [String]) {
|
||||
for url in acceptedPoliciesUrls {
|
||||
if let policyIndex = self.policies.firstIndex(where: { $0.url == url }) {
|
||||
checkedPolicies.insert(policyIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Actions
|
||||
|
||||
@IBAction private func acceptButtonAction(_ sender: Any) {
|
||||
self.viewModel.process(viewAction: .accept)
|
||||
}
|
||||
|
||||
private func cancelButtonAction() {
|
||||
self.viewModel.process(viewAction: .cancel)
|
||||
}
|
||||
|
||||
@objc private func didTapCheckbox(sender: UITapGestureRecognizer) {
|
||||
|
||||
guard let policyIndex = sender.view?.tag else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.checkedPolicies.contains(policyIndex) {
|
||||
self.checkedPolicies.remove(policyIndex)
|
||||
} else {
|
||||
checkedPolicies.insert(policyIndex)
|
||||
}
|
||||
|
||||
self.refreshViews()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - ServiceTermsModalScreenViewModelViewDelegate
|
||||
extension ServiceTermsModalScreenViewController: ServiceTermsModalScreenViewModelViewDelegate {
|
||||
|
||||
func serviceTermsModalScreenViewModel(_ viewModel: ServiceTermsModalScreenViewModelType, didUpdateViewState viewSate: ServiceTermsModalScreenViewState) {
|
||||
self.render(viewState: viewSate)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITableViewDataSource
|
||||
|
||||
extension ServiceTermsModalScreenViewController: UITableViewDataSource {
|
||||
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return self.policies.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
guard let cell = tableView.dequeueReusableCell(withIdentifier: TableViewCellWithCheckBoxAndLabel.defaultReuseIdentifier(), for: indexPath) as? TableViewCellWithCheckBoxAndLabel else {
|
||||
fatalError("\(String(describing: TableViewCellWithCheckBoxAndLabel.self)) should be registered")
|
||||
}
|
||||
|
||||
let policy = policies[indexPath.row]
|
||||
let checked = checkedPolicies.contains(indexPath.row)
|
||||
|
||||
cell.label.attributedText = self.cellLabel(for: policy)
|
||||
cell.label.font = .systemFont(ofSize: 15)
|
||||
cell.isEnabled = checked
|
||||
cell.accessoryType = .disclosureIndicator
|
||||
cell.backgroundColor = self.theme.backgroundColor
|
||||
|
||||
if let checkBox = cell.checkBox, checkBox.gestureRecognizers?.isEmpty ?? true {
|
||||
let gesture: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapCheckbox))
|
||||
gesture.numberOfTapsRequired = 1
|
||||
gesture.numberOfTouchesRequired = 1
|
||||
|
||||
checkBox.isUserInteractionEnabled = true
|
||||
checkBox.tag = indexPath.row
|
||||
checkBox.addGestureRecognizer(gesture)
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
func cellLabel(for policy: MXLoginPolicyData) -> NSAttributedString {
|
||||
|
||||
// TableViewCellWithCheckBoxAndLabel does not have a detailTextLabel
|
||||
// Do it by hand
|
||||
|
||||
var labelDetail: String = ""
|
||||
switch self.viewModel.serviceType {
|
||||
case MXServiceTypeIdentityService:
|
||||
labelDetail = VectorL10n.serviceTermsModalDescriptionForIdentityServer
|
||||
case MXServiceTypeIntegrationManager:
|
||||
labelDetail = VectorL10n.serviceTermsModalDescriptionForIntegrationManager
|
||||
default: break
|
||||
}
|
||||
|
||||
let label = NSMutableAttributedString(string: policy.name,
|
||||
attributes: [.foregroundColor: theme.textPrimaryColor])
|
||||
label.append(NSAttributedString(string: "\n"))
|
||||
label.append(NSAttributedString(string: labelDetail,
|
||||
attributes: [.foregroundColor: theme.textSecondaryColor]))
|
||||
|
||||
return label
|
||||
}
|
||||
}
|
||||
|
||||
extension ServiceTermsModalScreenViewController: UITableViewDelegate {
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
let policy = policies[indexPath.row]
|
||||
self.viewModel.process(viewAction: .display(policy))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
final class ServiceTermsModalScreenViewModel: ServiceTermsModalScreenViewModelType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let serviceTerms: MXServiceTerms
|
||||
|
||||
// MARK: Public
|
||||
|
||||
var serviceType: MXServiceType {
|
||||
return serviceTerms.serviceType
|
||||
}
|
||||
var policies: [MXLoginPolicyData]?
|
||||
var alreadyAcceptedPoliciesUrls: [String] = []
|
||||
|
||||
weak var viewDelegate: ServiceTermsModalScreenViewModelViewDelegate?
|
||||
weak var coordinatorDelegate: ServiceTermsModalScreenViewModelCoordinatorDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(serviceTerms: MXServiceTerms) {
|
||||
self.serviceTerms = serviceTerms
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func process(viewAction: ServiceTermsModalScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .load:
|
||||
self.loadTerms()
|
||||
case .display(let policy):
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModel(self, displayPolicy: policy)
|
||||
case .accept:
|
||||
self.acceptTerms()
|
||||
case .cancel:
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModelDidCancel(self)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func loadTerms() {
|
||||
|
||||
self.update(viewState: .loading)
|
||||
|
||||
self.serviceTerms.terms({ [weak self] (terms, alreadyAcceptedTermsUrls) in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let policies = self.processTerms(terms: terms)
|
||||
self.policies = policies
|
||||
self.alreadyAcceptedPoliciesUrls = alreadyAcceptedTermsUrls ?? []
|
||||
self.update(viewState: .loaded(policies: policies, alreadyAcceptedPoliciesUrls: self.alreadyAcceptedPoliciesUrls))
|
||||
|
||||
}, failure: { [weak self] error in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.update(viewState: .error(error))
|
||||
})
|
||||
}
|
||||
|
||||
private func acceptTerms() {
|
||||
|
||||
self.update(viewState: .loading)
|
||||
|
||||
self.serviceTerms.agree(toTerms: self.termsUrls, success: { [weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
self.update(viewState: .accepted)
|
||||
self.coordinatorDelegate?.serviceTermsModalScreenViewModelDidAccept(self)
|
||||
|
||||
}, failure: { [weak self] (error) in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.update(viewState: .error(error))
|
||||
})
|
||||
}
|
||||
|
||||
private func processTerms(terms: MXLoginTerms?) -> [MXLoginPolicyData] {
|
||||
if let policies = terms?.policiesData(forLanguage: Bundle.mxk_language(), defaultLanguage: Bundle.mxk_fallbackLanguage()) {
|
||||
return policies
|
||||
} else {
|
||||
print("[ServiceTermsModalScreenViewModel] processTerms: Error: No terms for \(String(describing: terms))")
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
private var termsUrls: [String] {
|
||||
guard let policies = self.policies else {
|
||||
return []
|
||||
}
|
||||
return policies.map({ return $0.url })
|
||||
}
|
||||
|
||||
private func update(viewState: ServiceTermsModalScreenViewState) {
|
||||
self.viewDelegate?.serviceTermsModalScreenViewModel(self, didUpdateViewState: viewState)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
protocol ServiceTermsModalScreenViewModelViewDelegate: class {
|
||||
func serviceTermsModalScreenViewModel(_ viewModel: ServiceTermsModalScreenViewModelType, didUpdateViewState viewSate: ServiceTermsModalScreenViewState)
|
||||
}
|
||||
|
||||
protocol ServiceTermsModalScreenViewModelCoordinatorDelegate: class {
|
||||
func serviceTermsModalScreenViewModel(_ coordinator: ServiceTermsModalScreenViewModelType, displayPolicy policy: MXLoginPolicyData)
|
||||
func serviceTermsModalScreenViewModelDidAccept(_ viewModel: ServiceTermsModalScreenViewModelType)
|
||||
func serviceTermsModalScreenViewModelDidCancel(_ viewModel: ServiceTermsModalScreenViewModelType)
|
||||
}
|
||||
|
||||
/// Protocol describing the view model used by `ServiceTermsModalScreenViewController`
|
||||
protocol ServiceTermsModalScreenViewModelType {
|
||||
|
||||
var serviceType: MXServiceType { get }
|
||||
var policies: [MXLoginPolicyData]? { get set }
|
||||
var alreadyAcceptedPoliciesUrls: [String] { get set }
|
||||
|
||||
var viewDelegate: ServiceTermsModalScreenViewModelViewDelegate? { get set }
|
||||
var coordinatorDelegate: ServiceTermsModalScreenViewModelCoordinatorDelegate? { get set }
|
||||
|
||||
func process(viewAction: ServiceTermsModalScreenViewAction)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// File created from ScreenTemplate
|
||||
// $ createScreen.sh Modal/Show ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
/// ServiceTermsModalScreenViewController view state
|
||||
enum ServiceTermsModalScreenViewState {
|
||||
case loading
|
||||
case loaded(policies: [MXLoginPolicyData], alreadyAcceptedPoliciesUrls: [String])
|
||||
case accepted
|
||||
case error(Error)
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
// File created from FlowTemplate
|
||||
// $ createRootCoordinator.sh Modal ServiceTermsModal ServiceTermsModalScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 UIKit
|
||||
|
||||
@objcMembers
|
||||
final class ServiceTermsModalCoordinator: ServiceTermsModalCoordinatorType {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let navigationRouter: NavigationRouterType
|
||||
private let session: MXSession
|
||||
private let serviceTerms: MXServiceTerms
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// Must be used only internally
|
||||
var childCoordinators: [Coordinator] = []
|
||||
|
||||
weak var delegate: ServiceTermsModalCoordinatorDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
init(session: MXSession, baseUrl: String, serviceType: MXServiceType, accessToken: String) {
|
||||
self.navigationRouter = NavigationRouter(navigationController: RiotNavigationController())
|
||||
self.session = session
|
||||
self.serviceTerms = MXServiceTerms(baseUrl: baseUrl, serviceType: serviceType, matrixSession: session, accessToken: accessToken)
|
||||
}
|
||||
|
||||
// MARK: - Public methods
|
||||
|
||||
func start() {
|
||||
let rootCoordinator = self.createServiceTermsModalLoadTermsScreenCoordinator()
|
||||
|
||||
rootCoordinator.start()
|
||||
|
||||
self.add(childCoordinator: rootCoordinator)
|
||||
|
||||
self.navigationRouter.setRootModule(rootCoordinator)
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.navigationRouter.toPresentable()
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
|
||||
private func createServiceTermsModalLoadTermsScreenCoordinator() -> ServiceTermsModalScreenCoordinator {
|
||||
let coordinator = ServiceTermsModalScreenCoordinator(serviceTerms: self.serviceTerms)
|
||||
coordinator.delegate = self
|
||||
return coordinator
|
||||
}
|
||||
|
||||
private func showPolicy(policy: MXLoginPolicyData) {
|
||||
// Display the policy webpage into our webview
|
||||
let webViewViewController: WebViewViewController = WebViewViewController(url: policy.url)
|
||||
webViewViewController.title = policy.name
|
||||
|
||||
let leftBarButtonItem: UIBarButtonItem = UIBarButtonItem(image: UIImage(named: "back_icon"), style: .plain, target: self, action: #selector(didTapCancelOnPolicyScreen))
|
||||
webViewViewController.navigationItem.leftBarButtonItem = leftBarButtonItem
|
||||
|
||||
self.navigationRouter.push(webViewViewController, animated: true, popCompletion: nil)
|
||||
}
|
||||
|
||||
private func removePolicyScreen() {
|
||||
self.navigationRouter.popModule(animated: true)
|
||||
}
|
||||
|
||||
@objc private func didTapCancelOnPolicyScreen() {
|
||||
self.removePolicyScreen()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ServiceTermsModalLoadTermsScreenCoordinatorDelegate
|
||||
extension ServiceTermsModalCoordinator: ServiceTermsModalScreenCoordinatorDelegate {
|
||||
|
||||
func serviceTermsModalScreenCoordinatorDidAccept(_ coordinator: ServiceTermsModalScreenCoordinatorType) {
|
||||
self.delegate?.serviceTermsModalCoordinatorDidAccept(self)
|
||||
}
|
||||
|
||||
func serviceTermsModalScreenCoordinator(_ coordinator: ServiceTermsModalScreenCoordinatorType, displayPolicy policy: MXLoginPolicyData) {
|
||||
self.showPolicy(policy: policy)
|
||||
}
|
||||
|
||||
func serviceTermsModalScreenCoordinatorDidCancel(_ coordinator: ServiceTermsModalScreenCoordinatorType) {
|
||||
self.delegate?.serviceTermsModalCoordinatorDidCancel(self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// File created from FlowTemplate
|
||||
// $ createRootCoordinator.sh Modal ServiceTermsModal ServiceTermsModalLoadTermsScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
@objc protocol ServiceTermsModalCoordinatorBridgePresenterDelegate {
|
||||
func serviceTermsModalCoordinatorBridgePresenterDelegateDidAccept(_ coordinatorBridgePresenter: ServiceTermsModalCoordinatorBridgePresenter)
|
||||
func serviceTermsModalCoordinatorBridgePresenterDelegateDidCancel(_ coordinatorBridgePresenter: ServiceTermsModalCoordinatorBridgePresenter)
|
||||
}
|
||||
|
||||
/// ServiceTermsModalCoordinatorBridgePresenter enables to start ServiceTermsModalCoordinator from a view controller.
|
||||
/// This bridge is used while waiting for global usage of coordinator pattern.
|
||||
@objcMembers
|
||||
final class ServiceTermsModalCoordinatorBridgePresenter: NSObject {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let session: MXSession
|
||||
private let baseUrl: String
|
||||
private let serviceType: MXServiceType
|
||||
private let accessToken: String
|
||||
private var coordinator: ServiceTermsModalCoordinator?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
weak var delegate: ServiceTermsModalCoordinatorBridgePresenterDelegate?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(session: MXSession, baseUrl: String, serviceType: MXServiceType, accessToken: String) {
|
||||
self.session = session
|
||||
self.baseUrl = baseUrl
|
||||
self.serviceType = serviceType
|
||||
self.accessToken = accessToken
|
||||
super.init()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
// NOTE: Default value feature is not compatible with Objective-C.
|
||||
// func present(from viewController: UIViewController, animated: Bool) {
|
||||
// self.present(from: viewController, animated: animated)
|
||||
// }
|
||||
|
||||
func present(from viewController: UIViewController, animated: Bool) {
|
||||
let serviceTermsModalCoordinator = ServiceTermsModalCoordinator(session: self.session, baseUrl: self.baseUrl, serviceType: self.serviceType, accessToken: accessToken)
|
||||
serviceTermsModalCoordinator.delegate = self
|
||||
viewController.present(serviceTermsModalCoordinator.toPresentable(), animated: animated, completion: nil)
|
||||
serviceTermsModalCoordinator.start()
|
||||
|
||||
self.coordinator = serviceTermsModalCoordinator
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool, completion: (() -> Void)?) {
|
||||
guard let coordinator = self.coordinator else {
|
||||
return
|
||||
}
|
||||
coordinator.toPresentable().dismiss(animated: animated) {
|
||||
self.coordinator = nil
|
||||
|
||||
if let completion = completion {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ServiceTermsModalCoordinatorDelegate
|
||||
extension ServiceTermsModalCoordinatorBridgePresenter: ServiceTermsModalCoordinatorDelegate {
|
||||
|
||||
func serviceTermsModalCoordinatorDidAccept(_ coordinator: ServiceTermsModalCoordinatorType) {
|
||||
self.delegate?.serviceTermsModalCoordinatorBridgePresenterDelegateDidAccept(self)
|
||||
}
|
||||
|
||||
func serviceTermsModalCoordinatorDidCancel(_ coordinator: ServiceTermsModalCoordinatorType) {
|
||||
self.delegate?.serviceTermsModalCoordinatorBridgePresenterDelegateDidCancel(self)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// File created from FlowTemplate
|
||||
// $ createRootCoordinator.sh Modal ServiceTermsModal ServiceTermsModalLoadTermsScreen
|
||||
/*
|
||||
Copyright 2019 New Vector 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 Foundation
|
||||
|
||||
protocol ServiceTermsModalCoordinatorDelegate: class {
|
||||
func serviceTermsModalCoordinatorDidAccept(_ coordinator: ServiceTermsModalCoordinatorType)
|
||||
func serviceTermsModalCoordinatorDidCancel(_ coordinator: ServiceTermsModalCoordinatorType)
|
||||
}
|
||||
|
||||
/// `ServiceTermsModalCoordinatorType` is a protocol describing a Coordinator that handle keybackup setup navigation flow.
|
||||
protocol ServiceTermsModalCoordinatorType: Coordinator, Presentable {
|
||||
var delegate: ServiceTermsModalCoordinatorDelegate? { get }
|
||||
}
|
||||
Reference in New Issue
Block a user