0

Add mediator and view for ShopCard

Bug: 374170663
Change-Id: Ied62c1e99cf07800118f3f8f1a281be59ffbb211
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6232968
Auto-Submit: Gloria Fang <gloriafang@google.com>
Reviewed-by: Chris Lu <thegreenfrog@chromium.org>
Commit-Queue: Chris Lu <thegreenfrog@chromium.org>
Reviewed-by: David Maunder <davidjm@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1416945}
This commit is contained in:
Gloria Fang
2025-02-06 11:55:30 -08:00
committed by Chromium LUCI CQ
parent f7512cd068
commit 75c7069b13
10 changed files with 300 additions and 0 deletions

@ -265,6 +265,7 @@ source_set("unit_tests") {
"//ios/chrome/browser/ui/content_suggestions/safety_check",
"//ios/chrome/browser/ui/content_suggestions/set_up_list",
"//ios/chrome/browser/ui/content_suggestions/set_up_list:utils",
"//ios/chrome/browser/ui/content_suggestions/shop_card:unit_tests",
"//ios/chrome/browser/ui/content_suggestions/tab_resumption",
"//ios/chrome/browser/ui/content_suggestions/tips",
"//ios/chrome/browser/url_loading/model",

@ -1,7 +1,12 @@
source_set("shop_card") {
sources = [
"shop_card_commands.h",
"shop_card_item.h",
"shop_card_item.mm",
"shop_card_mediator.h",
"shop_card_mediator.mm",
"shop_card_view.h",
"shop_card_view.mm",
]
deps = [
":shop_card_data",
@ -18,3 +23,20 @@ source_set("shop_card_data") {
]
deps = []
}
source_set("unit_tests") {
testonly = true
sources = [
"shop_card_mediator+testing.h",
"shop_card_mediator_unittest.mm",
]
deps = [
":shop_card",
"//components/commerce/core:shopping_service_test_support",
"//ios/chrome/browser/shared/public/commands:commands",
"//ios/chrome/test:test_support",
"//ios/web/public/test",
"//testing/gtest",
"//third_party/ocmock",
]
}

@ -0,0 +1,2 @@
davidjm@chromium.org
gloriafang@google.com

@ -0,0 +1,11 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_COMMANDS_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_COMMANDS_H_
// Command protocol for events of ShopCard module.
@protocol ShopCardCommands
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_COMMANDS_H_

@ -0,0 +1,27 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_TESTING_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_TESTING_H_
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_mediator.h"
@class ShopCardItem;
namespace commerce {
class ShoppingService;
} // namespace commerce
// Category for exposing internal state for testing.
@interface ShopCardMediator (ForTesting)
- (commerce::ShoppingService*)shoppingServiceForTesting;
- (ShopCardItem*)shopCardItemForTesting;
- (void)setShopCardItemForTesting:(ShopCardItem*)item;
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_TESTING_H_

@ -0,0 +1,45 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_H_
#import <UIKit/UIKit.h>
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_commands.h"
namespace commerce {
class ShoppingService;
}
@class ShopCardItem;
@class ShopCardData;
// Delegate to communicate events back to owner of ShopCardMediator.
@protocol ShopCardMediatorDelegate
- (void)removeShopCard;
@end
@interface ShopCardMediator : NSObject <ShopCardCommands>
// Default initializer.
- (instancetype)initWithShoppingService:
(commerce::ShoppingService*)shoppingService NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
- (void)disconnect;
- (void)reset;
- (void)disableModule;
- (ShopCardItem*)shopCardItemToShow;
// Delegate used to communicate events back to the owner of this class.
@property(nonatomic, weak) id<ShopCardMediatorDelegate> delegate;
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_MEDIATOR_H_

@ -0,0 +1,80 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_mediator.h"
#import "base/memory/raw_ptr.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_data.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_item.h"
@implementation ShopCardMediator {
raw_ptr<commerce::ShoppingService> _shoppingService;
ShopCardItem* _shopCardItem;
}
- (instancetype)initWithShoppingService:
(commerce::ShoppingService*)shoppingService {
self = [super init];
if (self) {
_shoppingService = shoppingService;
}
return self;
}
- (void)disconnect {
_shoppingService = nil;
}
- (void)reset {
_shopCardItem = nil;
}
- (void)setDelegate:(id<ShopCardMediatorDelegate>)delegate {
_delegate = delegate;
if (_delegate) {
[self fetchLatestShopCardItem];
}
}
- (void)fetchLatestShopCardItem {
// Populate the item if it is not already initialized.
// This is a placeholder and may get replaced when we fetch actual data.
if (self->_shopCardItem.shopCardData) {
return;
}
_shopCardItem = [[ShopCardItem alloc] init];
_shopCardItem.shopCardData = [[ShopCardData alloc] init];
// TODO: crbug.com/394638800 - set this to the correct type based on
// experiment.
_shopCardItem.shopCardData.shopCardItemType = ShopCardItemType::kUnknown;
}
- (ShopCardItem*)shopCardItemToShow {
return _shopCardItem;
}
#pragma mark - Public
- (void)disableModule {
}
#pragma mark - ShopCardMediatorDelegate
- (void)removeShopCard {
[self disableModule];
}
#pragma mark - Testing category methods
- (commerce::ShoppingService*)shoppingServiceForTesting {
return self->_shoppingService;
}
- (void)setShopCardItemForTesting:(ShopCardItem*)item {
self->_shopCardItem = item;
}
- (ShopCardItem*)shopCardItemForTesting {
return self->_shopCardItem;
}
@end

@ -0,0 +1,59 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_mediator.h"
#import "base/strings/sys_string_conversions.h"
#import "components/commerce/core/mock_shopping_service.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_item.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_mediator+testing.h"
#import "ios/web/public/test/web_task_environment.h"
#import "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#import "third_party/ocmock/gtest_support.h"
class ShopCardMediatorTest : public PlatformTest {
public:
ShopCardMediatorTest() {
shopping_service_ = std::make_unique<commerce::MockShoppingService>();
mediator_ = [[ShopCardMediator alloc]
initWithShoppingService:shopping_service_.get()];
}
~ShopCardMediatorTest() override {}
void TearDown() override { [mediator_ disconnect]; }
ShopCardMediator* mediator() { return mediator_; }
protected:
std::unique_ptr<commerce::MockShoppingService> shopping_service_;
ShopCardMediator* mediator_;
web::WebTaskEnvironment task_environment_;
};
// Test disconnecting the mediator.
TEST_F(ShopCardMediatorTest, TestDisconnect) {
EXPECT_NE(nil, mediator().shoppingServiceForTesting);
[mediator() disconnect];
EXPECT_EQ(nil, mediator().shoppingServiceForTesting);
}
// Resets card.
TEST_F(ShopCardMediatorTest, TestReset) {
ShopCardItem* item = [[ShopCardItem alloc] init];
[mediator() setShopCardItemForTesting:item];
EXPECT_NE(nil, mediator().shopCardItemForTesting);
[mediator() reset];
EXPECT_EQ(nil, mediator().shopCardItemForTesting);
}
TEST_F(ShopCardMediatorTest, TestRemoveShopCard) {
id mockDelegate = OCMStrictProtocolMock(@protocol(ShopCardMediatorDelegate));
OCMExpect([mockDelegate removeShopCard]);
mediator().delegate = mockDelegate;
[mediator() disableModule];
}

@ -0,0 +1,25 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_VIEW_H_
#define IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_VIEW_H_
#import <UIKit/UIKit.h>
@protocol ShopCardCommands;
@class ShopCardItem;
@interface ShopCardModuleView : UIView
- (instancetype)initWithFrame;
// Configures this view with `config`.
- (void)configureView:(ShopCardItem*)config;
// Command handler for user events.
@property(nonatomic, weak) id<ShopCardCommands> commandHandler;
@end
#endif // IOS_CHROME_BROWSER_UI_CONTENT_SUGGESTIONS_SHOP_CARD_SHOP_CARD_VIEW_H_

@ -0,0 +1,28 @@
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_view.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_data.h"
#import "ios/chrome/browser/ui/content_suggestions/shop_card/shop_card_item.h"
@implementation ShopCardModuleView {
}
- (instancetype)initWithFrame {
self = [super initWithFrame:CGRectZero];
return self;
}
- (void)configureView:(ShopCardItem*)config {
if (config.shopCardData.shopCardItemType ==
ShopCardItemType::kPriceDropOnTab) {
// TODO: crbug.com/394638800 - render correct view when data available
} else if (config.shopCardData.shopCardItemType ==
ShopCardItemType::kReviews) {
// TODO: crbug.com/394638800 - render correct view when data available
}
}
@end