Commit 7f33b43a authored by Jérôme Lebel's avatar Jérôme Lebel Committed by Commit Bot

[iOS] Fixing collapsible sections in Sync and Google Services

When signed out:
  - personalized section should be collapsed
  - non-personalized should be expanded

When signed-in with no consent given:
  - personalized section should be expanded
  - non-personalized should be expanded

When signed-in with consent given:
  - personalized section should be collapsed
  - non-personalized should be collapsed

Bug: 849838, 863860
Cq-Include-Trybots: luci.chromium.try:ios-simulator-full-configs;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: I4fa468253606c431684d0c8b19bcf4548dcf4ad7
Reviewed-on: https://chromium-review.googlesource.com/1133171
Commit-Queue: Jérôme Lebel <jlebel@chromium.org>
Reviewed-by: default avatarSergio Collazos <sczs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577477}
parent ce678e79
...@@ -141,6 +141,7 @@ source_set("settings") { ...@@ -141,6 +141,7 @@ source_set("settings") {
"//components/sync", "//components/sync",
"//components/translate/core/browser", "//components/translate/core/browser",
"//components/translate/core/common", "//components/translate/core/common",
"//components/unified_consent",
"//components/url_formatter", "//components/url_formatter",
"//components/version_info", "//components/version_info",
"//ios/chrome/app/strings", "//ios/chrome/app/strings",
...@@ -435,10 +436,13 @@ source_set("unified_consent_eg_tests") { ...@@ -435,10 +436,13 @@ source_set("unified_consent_eg_tests") {
"//base", "//base",
"//base/test:test_support", "//base/test:test_support",
"//components/signin/core/browser", "//components/signin/core/browser",
"//components/unified_consent",
"//ios/chrome/app/strings:ios_chromium_strings_grit", "//ios/chrome/app/strings:ios_chromium_strings_grit",
"//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/app/strings:ios_strings_grit",
"//ios/chrome/browser/browser_state",
"//ios/chrome/browser/ui:ui_util", "//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/authentication:eg_test_support", "//ios/chrome/browser/ui/authentication:eg_test_support",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support", "//ios/chrome/test/earl_grey:test_support",
"//ui/base", "//ui/base",
] ]
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h" #import "ios/chrome/browser/ui/settings/google_services_settings_coordinator.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_factory.h"
#import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h" #import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h"
#import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h" #import "ios/chrome/browser/ui/settings/google_services_settings_view_controller.h"
...@@ -34,7 +35,8 @@ ...@@ -34,7 +35,8 @@
style:CollectionViewControllerStyleAppBar]; style:CollectionViewControllerStyleAppBar];
controller.presentationDelegate = self; controller.presentationDelegate = self;
self.viewController = controller; self.viewController = controller;
self.mediator = [[GoogleServicesSettingsMediator alloc] init]; self.mediator = [[GoogleServicesSettingsMediator alloc]
initWithPrefService:self.browserState->GetPrefs()];
self.mediator.consumer = controller; self.mediator.consumer = controller;
self.mediator.authService = self.mediator.authService =
AuthenticationServiceFactory::GetForBrowserState(self.browserState); AuthenticationServiceFactory::GetForBrowserState(self.browserState);
......
...@@ -5,9 +5,15 @@ ...@@ -5,9 +5,15 @@
#import <EarlGrey/EarlGrey.h> #import <EarlGrey/EarlGrey.h>
#import <XCTest/XCTest.h> #import <XCTest/XCTest.h>
#include "components/prefs/pref_service.h"
#include "components/unified_consent/pref_names.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
#import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
#include "ios/chrome/browser/ui/ui_util.h" #include "ios/chrome/browser/ui/ui_util.h"
#include "ios/chrome/grit/ios_chromium_strings.h" #include "ios/chrome/grit/ios_chromium_strings.h"
#include "ios/chrome/grit/ios_strings.h" #include "ios/chrome/grit/ios_strings.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#include "ios/chrome/test/earl_grey/accessibility_util.h" #include "ios/chrome/test/earl_grey/accessibility_util.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h"
...@@ -19,20 +25,22 @@ ...@@ -19,20 +25,22 @@
#endif #endif
using l10n_util::GetNSString; using l10n_util::GetNSString;
using chrome_test_util::GetOriginalBrowserState;
using chrome_test_util::GoogleServicesSettingsButton; using chrome_test_util::GoogleServicesSettingsButton;
using chrome_test_util::SettingsMenuBackButton; using chrome_test_util::SettingsMenuBackButton;
using chrome_test_util::SettingsDoneButton; using chrome_test_util::SettingsDoneButton;
using unified_consent::prefs::kUnifiedConsentGiven;
// Integration tests using the Google services settings screen. // Integration tests using the Google services settings screen.
@interface GoogleServicesSettingsTestCase : ChromeTestCase @interface GoogleServicesSettingsTestCase : ChromeTestCase
@property(nonatomic, strong) id<GREYMatcher> scollViewMatcher; @property(nonatomic, strong) id<GREYMatcher> scrollViewMatcher;
@end @end
@implementation GoogleServicesSettingsTestCase @implementation GoogleServicesSettingsTestCase
@synthesize scollViewMatcher = _scollViewMatcher; @synthesize scrollViewMatcher = _scrollViewMatcher;
// Opens the Google services settings view, and closes it. // Opens the Google services settings view, and closes it.
- (void)testOpenGoogleServicesSettings { - (void)testOpenGoogleServicesSettings {
...@@ -41,9 +49,7 @@ using chrome_test_util::SettingsDoneButton; ...@@ -41,9 +49,7 @@ using chrome_test_util::SettingsDoneButton;
[self openGoogleServicesSettings]; [self openGoogleServicesSettings];
// Assert title and accessibility. // Assert title and accessibility.
[[EarlGrey [[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
selectElementWithMatcher:grey_accessibilityID(
@"google_services_settings_view_controller")]
assertWithMatcher:grey_notNil()]; assertWithMatcher:grey_notNil()];
chrome_test_util::VerifyAccessibilityForCurrentScreen(); chrome_test_util::VerifyAccessibilityForCurrentScreen();
...@@ -54,18 +60,75 @@ using chrome_test_util::SettingsDoneButton; ...@@ -54,18 +60,75 @@ using chrome_test_util::SettingsDoneButton;
performAction:grey_tap()]; performAction:grey_tap()];
} }
// Tests if the Google Services settings contains only the non personalized // Tests the Google Services settings, when the user is not logged in.
// options when the user is not logged in. // The personalized section is expect to be collapsed and the non-personalized
- (void)testServicesWhileSignedOut { // section is expected to be expanded.
// TODO(crbug.com/863860): re-enable when fixed. - (void)testOpeningServicesWhileSignedOut {
if (!IsIPadIdiom()) if (!IsUIRefreshPhase1Enabled())
EARL_GREY_TEST_DISABLED(@"Fails on iPhones."); EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
[self openGoogleServicesSettings];
[self assertPersonalizedServicesCollapsed:YES];
[self assertNonPersonalizedServicesCollapsed:NO];
}
// Tests the Google Services settings, when the user is logged in without user
// consent.
// The "Sync Everything" section is expected to be visible.
// The personalized section and the non-personalized section are expected to be
// expanded.
- (void)testOpeningServicesWhileSignedIn {
if (!IsUIRefreshPhase1Enabled()) if (!IsUIRefreshPhase1Enabled())
EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only."); EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
PrefService* prefService = GetOriginalBrowserState()->GetPrefs();
prefService->SetBoolean(kUnifiedConsentGiven, false);
[SigninEarlGreyUI signinWithIdentity:[SigninEarlGreyUtils fakeIdentity1]];
[self openGoogleServicesSettings]; [self openGoogleServicesSettings];
[self assertSyncPersonalizedServicesCollapsed:YES]; [self assertSyncEverythingSection];
[self assertPersonalizedServicesCollapsed:NO];
[self assertNonPersonalizedServicesCollapsed:NO]; [self assertNonPersonalizedServicesCollapsed:NO];
}
// Tests the Google Services settings, when the user is logged in with user
// consent.
// The "Sync Everything" section is expected to be visible.
// The personalized section and the non-personalized section are expected to be
// collapsed.
- (void)testOpeningServicesWhileSignedInAndConsentGiven {
if (!IsUIRefreshPhase1Enabled())
EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
PrefService* prefService = GetOriginalBrowserState()->GetPrefs();
prefService->SetBoolean(kUnifiedConsentGiven, true);
[SigninEarlGreyUI signinWithIdentity:[SigninEarlGreyUtils fakeIdentity1]];
[self openGoogleServicesSettings];
[self assertSyncEverythingSection];
[self assertPersonalizedServicesCollapsed:YES];
[self assertNonPersonalizedServicesCollapsed:YES];
}
// Tests to expand/collapse the personalized section.
- (void)testTogglePersonalizedServices {
if (!IsUIRefreshPhase1Enabled())
EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
[self openGoogleServicesSettings];
[self assertPersonalizedServicesCollapsed:YES];
[self togglePersonalizedServicesSection];
[self assertPersonalizedServicesCollapsed:NO];
[[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
performAction:grey_scrollToContentEdgeWithStartPoint(kGREYContentEdgeTop,
0.1f, 0.1f)];
[self togglePersonalizedServicesSection];
[self assertPersonalizedServicesCollapsed:YES];
}
// Tests to expand/collapse the non-personalized section.
- (void)testToggleNonPersonalizedServices {
if (!IsUIRefreshPhase1Enabled())
EARL_GREY_TEST_SKIPPED(@"This test is UIRefresh only.");
[self openGoogleServicesSettings];
[self assertNonPersonalizedServicesCollapsed:NO];
[[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
performAction:grey_scrollToContentEdgeWithStartPoint(kGREYContentEdgeTop,
0.1f, 0.1f)];
[self toggleNonPersonalizedServicesSection]; [self toggleNonPersonalizedServicesSection];
[self assertNonPersonalizedServicesCollapsed:YES]; [self assertNonPersonalizedServicesCollapsed:YES];
[self toggleNonPersonalizedServicesSection]; [self toggleNonPersonalizedServicesSection];
...@@ -77,12 +140,20 @@ using chrome_test_util::SettingsDoneButton; ...@@ -77,12 +140,20 @@ using chrome_test_util::SettingsDoneButton;
- (void)openGoogleServicesSettings { - (void)openGoogleServicesSettings {
[ChromeEarlGreyUI openSettingsMenu]; [ChromeEarlGreyUI openSettingsMenu];
[ChromeEarlGreyUI tapSettingsMenuButton:GoogleServicesSettingsButton()]; [ChromeEarlGreyUI tapSettingsMenuButton:GoogleServicesSettingsButton()];
self.scollViewMatcher = self.scrollViewMatcher =
grey_accessibilityID(@"google_services_settings_view_controller"); grey_accessibilityID(@"google_services_settings_view_controller");
[[EarlGrey selectElementWithMatcher:self.scollViewMatcher] [[EarlGrey selectElementWithMatcher:self.scrollViewMatcher]
assertWithMatcher:grey_notNil()]; assertWithMatcher:grey_notNil()];
} }
- (void)togglePersonalizedServicesSection {
[[EarlGrey
selectElementWithMatcher:
grey_accessibilityLabel(GetNSString(
IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_PERSONALIZATION_TEXT))]
performAction:grey_tap()];
}
- (void)toggleNonPersonalizedServicesSection { - (void)toggleNonPersonalizedServicesSection {
[[EarlGrey [[EarlGrey
selectElementWithMatcher: selectElementWithMatcher:
...@@ -92,18 +163,21 @@ using chrome_test_util::SettingsDoneButton; ...@@ -92,18 +163,21 @@ using chrome_test_util::SettingsDoneButton;
} }
- (void)assertCellWithTitleID:(int)titleID detailTextID:(int)detailTextID { - (void)assertCellWithTitleID:(int)titleID detailTextID:(int)detailTextID {
NSString* accessibilityLabel = GetNSString(titleID);
if (detailTextID) {
accessibilityLabel =
[NSString stringWithFormat:@"%@, %@", accessibilityLabel,
GetNSString(detailTextID)];
}
[[[EarlGrey [[[EarlGrey
selectElementWithMatcher:grey_accessibilityLabel(GetNSString(titleID))] selectElementWithMatcher:grey_allOf(
grey_accessibilityLabel(accessibilityLabel),
grey_kindOfClass(
[UICollectionViewCell class]),
grey_sufficientlyVisible(), nil)]
usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp) usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
onElementWithMatcher:self.scollViewMatcher] onElementWithMatcher:self.scrollViewMatcher]
assertWithMatcher:grey_notNil()]; assertWithMatcher:grey_notNil()];
if (detailTextID) {
[[[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
GetNSString(detailTextID))]
usingSearchAction:grey_swipeSlowInDirection(kGREYDirectionUp)
onElementWithMatcher:self.scollViewMatcher]
assertWithMatcher:grey_notNil()];
}
} }
- (void)assertSyncEverythingSection { - (void)assertSyncEverythingSection {
...@@ -111,7 +185,7 @@ using chrome_test_util::SettingsDoneButton; ...@@ -111,7 +185,7 @@ using chrome_test_util::SettingsDoneButton;
detailTextID:0]; detailTextID:0];
} }
- (void)assertSyncPersonalizedServicesCollapsed:(BOOL)collapsed { - (void)assertPersonalizedServicesCollapsed:(BOOL)collapsed {
[self [self
assertCellWithTitleID: assertCellWithTitleID:
IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_PERSONALIZATION_TEXT IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_PERSONALIZATION_TEXT
......
...@@ -13,11 +13,18 @@ ...@@ -13,11 +13,18 @@
class AuthenticationService; class AuthenticationService;
@class GoogleServicesSettingsViewController; @class GoogleServicesSettingsViewController;
class PrefService;
// Mediator for the Google services settings. // Mediator for the Google services settings.
@interface GoogleServicesSettingsMediator @interface GoogleServicesSettingsMediator
: NSObject<GoogleServicesSettingsViewControllerModelDelegate> : NSObject<GoogleServicesSettingsViewControllerModelDelegate>
// Designated initializer. |prefService| should not be null.
- (instancetype)initWithPrefService:(PrefService*)prefService
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
// View controller. // View controller.
@property(nonatomic, weak) id<GoogleServicesSettingsConsumer> consumer; @property(nonatomic, weak) id<GoogleServicesSettingsConsumer> consumer;
// Browser state. // Browser state.
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h" #import "ios/chrome/browser/ui/settings/google_services_settings_mediator.h"
#include "components/prefs/pref_service.h"
#include "components/unified_consent/pref_names.h"
#import "ios/chrome/browser/signin/authentication_service.h" #import "ios/chrome/browser/signin/authentication_service.h"
#import "ios/chrome/browser/signin/authentication_service_factory.h" #import "ios/chrome/browser/signin/authentication_service_factory.h"
#import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h" #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
...@@ -20,6 +22,7 @@ ...@@ -20,6 +22,7 @@
#endif #endif
using l10n_util::GetNSString; using l10n_util::GetNSString;
using unified_consent::prefs::kUnifiedConsentGiven;
namespace { namespace {
...@@ -67,6 +70,8 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -67,6 +70,8 @@ typedef NS_ENUM(NSInteger, ItemType) {
// Returns YES if the user is authenticated. // Returns YES if the user is authenticated.
@property(nonatomic, readonly) BOOL isAuthenticated; @property(nonatomic, readonly) BOOL isAuthenticated;
// Preference service.
@property(nonatomic, readonly) PrefService* prefService;
@end @end
...@@ -74,9 +79,19 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -74,9 +79,19 @@ typedef NS_ENUM(NSInteger, ItemType) {
@synthesize consumer = _consumer; @synthesize consumer = _consumer;
@synthesize authService = _authService; @synthesize authService = _authService;
@synthesize prefService = _prefService;
#pragma mark - Load model #pragma mark - Load model
- (instancetype)initWithPrefService:(PrefService*)prefService {
self = [super init];
if (self) {
DCHECK(prefService);
_prefService = prefService;
}
return self;
}
// Loads SyncEverythingSectionIdentifier section. // Loads SyncEverythingSectionIdentifier section.
- (void)loadSyncEverythingSection { - (void)loadSyncEverythingSection {
CollectionViewModel* model = self.consumer.collectionViewModel; CollectionViewModel* model = self.consumer.collectionViewModel;
...@@ -91,6 +106,7 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -91,6 +106,7 @@ typedef NS_ENUM(NSInteger, ItemType) {
[[SyncSwitchItem alloc] initWithType:SyncEverythingItemType]; [[SyncSwitchItem alloc] initWithType:SyncEverythingItemType];
item.text = GetNSString(IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_EVERYTHING); item.text = GetNSString(IDS_IOS_GOOGLE_SERVICES_SETTINGS_SYNC_EVERYTHING);
item.enabled = YES; item.enabled = YES;
item.on = [self isConsentGiven];
return item; return item;
} }
...@@ -102,10 +118,11 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -102,10 +118,11 @@ typedef NS_ENUM(NSInteger, ItemType) {
collapsedKey:kGoogleServicesSettingsPersonalizedSectionKey]; collapsedKey:kGoogleServicesSettingsPersonalizedSectionKey];
SettingsCollapsibleItem* syncPersonalizationItem = SettingsCollapsibleItem* syncPersonalizationItem =
[self syncPersonalizationItem]; [self syncPersonalizationItem];
syncPersonalizationItem.collapsed =
[model sectionIsCollapsed:PersonalizedSectionIdentifier];
[model addItem:syncPersonalizationItem [model addItem:syncPersonalizationItem
toSectionWithIdentifier:PersonalizedSectionIdentifier]; toSectionWithIdentifier:PersonalizedSectionIdentifier];
BOOL collapsed = self.isAuthenticated ? [self isConsentGiven] : YES;
syncPersonalizationItem.collapsed = collapsed;
[model setSection:PersonalizedSectionIdentifier collapsed:collapsed];
[model addItem:[self syncBookmarksItem] [model addItem:[self syncBookmarksItem]
toSectionWithIdentifier:PersonalizedSectionIdentifier]; toSectionWithIdentifier:PersonalizedSectionIdentifier];
[model addItem:[self syncHistoryItem] [model addItem:[self syncHistoryItem]
...@@ -126,8 +143,6 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -126,8 +143,6 @@ typedef NS_ENUM(NSInteger, ItemType) {
toSectionWithIdentifier:PersonalizedSectionIdentifier]; toSectionWithIdentifier:PersonalizedSectionIdentifier];
[model addItem:[self manageSyncedDataItem] [model addItem:[self manageSyncedDataItem]
toSectionWithIdentifier:PersonalizedSectionIdentifier]; toSectionWithIdentifier:PersonalizedSectionIdentifier];
[model setSection:PersonalizedSectionIdentifier
collapsed:!self.isAuthenticated];
} }
// Creates SyncPersonalizationItemType item. // Creates SyncPersonalizationItemType item.
...@@ -260,10 +275,11 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -260,10 +275,11 @@ typedef NS_ENUM(NSInteger, ItemType) {
collapsedKey:kGoogleServicesSettingsNonPersonalizedSectionKey]; collapsedKey:kGoogleServicesSettingsNonPersonalizedSectionKey];
SettingsCollapsibleItem* nonPersonalizedServicesItem = SettingsCollapsibleItem* nonPersonalizedServicesItem =
[self nonPersonalizedServicesItem]; [self nonPersonalizedServicesItem];
nonPersonalizedServicesItem.collapsed =
[model sectionIsCollapsed:NonPersonalizedSectionIdentifier];
[model addItem:nonPersonalizedServicesItem [model addItem:nonPersonalizedServicesItem
toSectionWithIdentifier:NonPersonalizedSectionIdentifier]; toSectionWithIdentifier:NonPersonalizedSectionIdentifier];
BOOL collapsed = self.isAuthenticated ? [self isConsentGiven] : NO;
nonPersonalizedServicesItem.collapsed = collapsed;
[model setSection:NonPersonalizedSectionIdentifier collapsed:collapsed];
[model addItem:[self autocompleteSearchesAndURLsItem] [model addItem:[self autocompleteSearchesAndURLsItem]
toSectionWithIdentifier:NonPersonalizedSectionIdentifier]; toSectionWithIdentifier:NonPersonalizedSectionIdentifier];
[model addItem:[self preloadPagesItem] [model addItem:[self preloadPagesItem]
...@@ -272,7 +288,6 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -272,7 +288,6 @@ typedef NS_ENUM(NSInteger, ItemType) {
toSectionWithIdentifier:NonPersonalizedSectionIdentifier]; toSectionWithIdentifier:NonPersonalizedSectionIdentifier];
[model addItem:[self betterSearchAndBrowsingItemType] [model addItem:[self betterSearchAndBrowsingItemType]
toSectionWithIdentifier:NonPersonalizedSectionIdentifier]; toSectionWithIdentifier:NonPersonalizedSectionIdentifier];
[model setSection:PersonalizedSectionIdentifier collapsed:YES];
} }
// Creates NonPersonalizedServicesItemType item. // Creates NonPersonalizedServicesItemType item.
...@@ -340,6 +355,10 @@ typedef NS_ENUM(NSInteger, ItemType) { ...@@ -340,6 +355,10 @@ typedef NS_ENUM(NSInteger, ItemType) {
return self.authService->IsAuthenticated(); return self.authService->IsAuthenticated();
} }
- (BOOL)isConsentGiven {
return self.prefService->GetBoolean(kUnifiedConsentGiven);
}
#pragma mark - GoogleServicesSettingsViewControllerModelDelegate #pragma mark - GoogleServicesSettingsViewControllerModelDelegate
- (void)googleServicesSettingsViewControllerLoadModel: - (void)googleServicesSettingsViewControllerLoadModel:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment