Commit 649e1d1b authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Created FullscreenMediator.

This intermediary object listens to changes from the FullscreenModel
and propagates them to FullscreenControllerObservers.

Bug: 785671
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I925ad42aec3acb11f6562d591121dad3476a9d2a
Reviewed-on: https://chromium-review.googlesource.com/794951
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Reviewed-by: default avatarKurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521553}
parent 02925c41
...@@ -43,6 +43,8 @@ source_set("new_fullscreen_internal") { ...@@ -43,6 +43,8 @@ source_set("new_fullscreen_internal") {
sources = [ sources = [
"fullscreen_controller.mm", "fullscreen_controller.mm",
"fullscreen_controller_factory.mm", "fullscreen_controller_factory.mm",
"fullscreen_mediator.h",
"fullscreen_mediator.mm",
"fullscreen_model.h", "fullscreen_model.h",
"fullscreen_model.mm", "fullscreen_model.mm",
"fullscreen_model_observer.h", "fullscreen_model_observer.h",
...@@ -88,6 +90,7 @@ source_set("new_fullscreen_ui") { ...@@ -88,6 +90,7 @@ source_set("new_fullscreen_ui") {
source_set("new_unit_tests") { source_set("new_unit_tests") {
testonly = true testonly = true
sources = [ sources = [
"fullscreen_mediator_unittest.mm",
"fullscreen_model_unittest.mm", "fullscreen_model_unittest.mm",
"fullscreen_ui_updater_unittest.mm", "fullscreen_ui_updater_unittest.mm",
"fullscreen_web_state_list_observer_unittest.mm", "fullscreen_web_state_list_observer_unittest.mm",
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
@class ChromeBroadcaster; @class ChromeBroadcaster;
@class ChromeBroadcastOberverBridge; @class ChromeBroadcastOberverBridge;
class FullscreenControllerObserver; class FullscreenControllerObserver;
class FullscreenMediator;
class FullscreenModel; class FullscreenModel;
class FullscreenWebStateListObserver; class FullscreenWebStateListObserver;
...@@ -59,6 +60,8 @@ class FullscreenController : public KeyedService { ...@@ -59,6 +60,8 @@ class FullscreenController : public KeyedService {
std::unique_ptr<FullscreenModel> model_; std::unique_ptr<FullscreenModel> model_;
// The bridge used to forward brodcasted UI to |model_|. // The bridge used to forward brodcasted UI to |model_|.
__strong ChromeBroadcastOberverBridge* bridge_ = nil; __strong ChromeBroadcastOberverBridge* bridge_ = nil;
// Object that manages sending signals to FullscreenControllerObservers.
std::unique_ptr<FullscreenMediator> mediator_;
// A WebStateListObserver that updates |model_| for WebStateList changes. // A WebStateListObserver that updates |model_| for WebStateList changes.
std::unique_ptr<FullscreenWebStateListObserver> web_state_list_observer_; std::unique_ptr<FullscreenWebStateListObserver> web_state_list_observer_;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcast_observer_bridge.h" #import "ios/chrome/browser/ui/broadcaster/chrome_broadcast_observer_bridge.h"
#import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h" #import "ios/chrome/browser/ui/broadcaster/chrome_broadcaster.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_mediator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h" #import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h"
...@@ -17,8 +18,9 @@ ...@@ -17,8 +18,9 @@
FullscreenController::FullscreenController() FullscreenController::FullscreenController()
: broadcaster_([[ChromeBroadcaster alloc] init]), : broadcaster_([[ChromeBroadcaster alloc] init]),
model_(base::MakeUnique<FullscreenModel>()), model_(base::MakeUnique<FullscreenModel>()),
bridge_([[ChromeBroadcastOberverBridge alloc] bridge_(
initWithObserver:model_.get()]) { [[ChromeBroadcastOberverBridge alloc] initWithObserver:model_.get()]),
mediator_(base::MakeUnique<FullscreenMediator>(this, model_.get())) {
DCHECK(broadcaster_); DCHECK(broadcaster_);
[broadcaster_ addObserver:bridge_ [broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)]; forSelector:@selector(broadcastContentScrollOffset:)];
...@@ -33,14 +35,12 @@ FullscreenController::FullscreenController() ...@@ -33,14 +35,12 @@ FullscreenController::FullscreenController()
FullscreenController::~FullscreenController() = default; FullscreenController::~FullscreenController() = default;
void FullscreenController::AddObserver(FullscreenControllerObserver* observer) { void FullscreenController::AddObserver(FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep mediator_->AddObserver(observer);
// track of observers.
} }
void FullscreenController::RemoveObserver( void FullscreenController::RemoveObserver(
FullscreenControllerObserver* observer) { FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep mediator_->RemoveObserver(observer);
// track of observers.
} }
bool FullscreenController::IsEnabled() const { bool FullscreenController::IsEnabled() const {
...@@ -56,6 +56,7 @@ void FullscreenController::DecrementDisabledCounter() { ...@@ -56,6 +56,7 @@ void FullscreenController::DecrementDisabledCounter() {
} }
void FullscreenController::Shutdown() { void FullscreenController::Shutdown() {
mediator_->Disconnect();
[broadcaster_ removeObserver:bridge_ [broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)]; forSelector:@selector(broadcastContentScrollOffset:)];
[broadcaster_ removeObserver:bridge_ [broadcaster_ removeObserver:bridge_
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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_FULLSCREEN_FULLSCREEN_MEDIATOR_H_
#define IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_MEDIATOR_H_
#import <Foundation/Foundation.h>
#include <memory>
#include "base/macros.h"
#include "base/observer_list.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model_observer.h"
class FullscreenController;
class FullscreenControllerObserver;
@class FullscreenScrollEndAnimator;
// A helper object that listens to FullscreenModel changes and forwards this
// information to FullscreenControllerObservers.
class FullscreenMediator : public FullscreenModelObserver {
public:
FullscreenMediator(FullscreenController* controller, FullscreenModel* model);
~FullscreenMediator() override;
// Adds and removes FullscreenControllerObservers.
void AddObserver(FullscreenControllerObserver* observer) {
observers_.AddObserver(observer);
}
void RemoveObserver(FullscreenControllerObserver* observer) {
observers_.RemoveObserver(observer);
}
// Instructs the manager to stop observing its model.
void Disconnect();
private:
// FullscreenModelObserver:
void FullscreenModelProgressUpdated(FullscreenModel* model) override;
void FullscreenModelEnabledStateChanged(FullscreenModel* model) override;
void FullscreenModelScrollEventEnded(FullscreenModel* model) override;
// Stops the current scroll end animation if one is in progress.
void StopAnimating();
// Performs cleanup tasks for the animator.
void CleanUpAnimator();
// The controller.
FullscreenController* controller_ = nullptr;
// The model.
FullscreenModel* model_ = nullptr;
// The scroll end animator passed to observers.
__strong FullscreenScrollEndAnimator* animator_ = nil;
// The FullscreenControllerObservers that need to get notified of model
// changes.
base::ObserverList<FullscreenControllerObserver> observers_;
DISALLOW_COPY_AND_ASSIGN(FullscreenMediator);
};
#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_MEDIATOR_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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/fullscreen/fullscreen_mediator.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
FullscreenMediator::FullscreenMediator(FullscreenController* controller,
FullscreenModel* model)
: controller_(controller), model_(model) {
DCHECK(controller_);
DCHECK(model_);
model_->AddObserver(this);
}
FullscreenMediator::~FullscreenMediator() {
// Disconnect() is expected to be called before deallocation.
DCHECK(!controller_);
DCHECK(!model_);
}
void FullscreenMediator::Disconnect() {
[animator_ stopAnimation:YES];
animator_ = nil;
model_->RemoveObserver(this);
model_ = nullptr;
controller_ = nullptr;
}
void FullscreenMediator::FullscreenModelProgressUpdated(
FullscreenModel* model) {
DCHECK_EQ(model_, model);
StopAnimating();
for (auto& observer : observers_) {
observer.FullscreenProgressUpdated(controller_, model_->progress());
}
}
void FullscreenMediator::FullscreenModelEnabledStateChanged(
FullscreenModel* model) {
DCHECK_EQ(model_, model);
StopAnimating();
for (auto& observer : observers_) {
observer.FullscreenEnabledStateChanged(controller_, model->enabled());
}
}
void FullscreenMediator::FullscreenModelScrollEventEnded(
FullscreenModel* model) {
DCHECK_EQ(model_, model);
DCHECK(!animator_);
animator_ = [[FullscreenScrollEndAnimator alloc]
initWithStartProgress:model_->progress()];
[animator_ addCompletion:^(UIViewAnimatingPosition finalPosition) {
CleanUpAnimator();
}];
for (auto& observer : observers_) {
observer.FullscreenScrollEventEnded(controller_, animator_);
}
[animator_ startAnimation];
}
void FullscreenMediator::StopAnimating() {
if (!animator_)
return;
DCHECK_EQ(animator_.state, UIViewAnimatingStateActive);
[animator_ stopAnimation:NO];
[animator_ finishAnimationAtPosition:UIViewAnimatingPositionCurrent];
}
void FullscreenMediator::CleanUpAnimator() {
DCHECK(animator_);
model_->AnimationEndedWithProgress(animator_.currentProgress);
animator_ = nil;
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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/fullscreen/fullscreen_mediator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
#import "ios/chrome/browser/ui/fullscreen/test/fullscreen_model_test_util.h"
#import "ios/chrome/browser/ui/fullscreen/test/test_fullscreen_controller_observer.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Test fixture for FullscreenMediator.
class FullscreenMediatorTest : public PlatformTest {
public:
FullscreenMediatorTest()
: PlatformTest(), observer_manager_(controller(), &model_) {
SetUpFullscreenModelForTesting(&model_, 100);
observer_manager_.AddObserver(&observer_);
}
~FullscreenMediatorTest() override {
observer_manager_.RemoveObserver(&observer_);
observer_manager_.Disconnect();
}
FullscreenController* controller() {
// TestFullscreenControllerObserver doesn't use the FullscreenController
// passed to its observer methods, so use a dummy pointer.
static void* kFullscreenController = &kFullscreenController;
return reinterpret_cast<FullscreenController*>(kFullscreenController);
}
FullscreenModel& model() { return model_; }
TestFullscreenControllerObserver& observer() { return observer_; }
private:
FullscreenModel model_;
FullscreenMediator observer_manager_;
TestFullscreenControllerObserver observer_;
};
// Tests that progress and scroll end animator are correctly forwarded to the
// observer.
TEST_F(FullscreenMediatorTest, ObserveProgressAndScrollEnd) {
SimulateFullscreenUserScrollForProgress(&model(), 0.5);
EXPECT_EQ(observer().progress(), 0.5);
FullscreenScrollEndAnimator* animator = observer().animator();
EXPECT_TRUE(animator);
EXPECT_EQ(animator.startProgress, 0.5);
EXPECT_EQ(animator.finalProgress, 1.0);
}
// Tests that the enabled state is correctly forwarded to the observer.
TEST_F(FullscreenMediatorTest, ObserveEnabledState) {
EXPECT_TRUE(observer().enabled());
model().IncrementDisabledCounter();
EXPECT_FALSE(observer().enabled());
model().DecrementDisabledCounter();
EXPECT_TRUE(observer().enabled());
}
...@@ -16,83 +16,31 @@ ...@@ -16,83 +16,31 @@
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
@interface FullscreenScrollEndTimingCurveProvider @interface FullscreenScrollEndAnimator () {
: NSObject<UITimingCurveProvider> { // The bezier backing the timing curve.
std::unique_ptr<gfx::CubicBezier> _bezier; std::unique_ptr<gfx::CubicBezier> _bezier;
} }
// The bezier backing the timing curve.
@property(nonatomic, readonly) const gfx::CubicBezier& bezier;
@end
@implementation FullscreenScrollEndTimingCurveProvider
- (instancetype)init {
if (self = [super init]) {
// Control points for Material Design CurveEaseOut curve.
_bezier = base::MakeUnique<gfx::CubicBezier>(0.0, 0.0, 0.2, 0.1);
}
return self;
}
#pragma mark Accessors
- (const gfx::CubicBezier&)bezier {
return *_bezier.get();
}
#pragma mark UITimingCurveProvider
- (UITimingCurveType)timingCurveType {
return UITimingCurveTypeCubic;
}
- (UICubicTimingParameters*)cubicTimingParameters {
return [[UICubicTimingParameters alloc]
initWithControlPoint1:CGPointMake(_bezier->GetX1(), _bezier->GetY1())
controlPoint2:CGPointMake(_bezier->GetX2(), _bezier->GetX2())];
}
- (UISpringTimingParameters*)springTimingParameters {
return nil;
}
#pragma mark NSCoding
- (void)encodeWithCoder:(NSCoder*)aCoder {
}
- (instancetype)initWithCoder:(NSCoder*)aDecoder {
return [[FullscreenScrollEndTimingCurveProvider alloc] init];
}
#pragma mark NSCopying
- (instancetype)copyWithZone:(NSZone*)zone {
return [[FullscreenScrollEndTimingCurveProvider alloc] init];
}
@end
@interface FullscreenScrollEndAnimator ()
@property(nonatomic, readonly) FullscreenScrollEndTimingCurveProvider* curve;
@end @end
@implementation FullscreenScrollEndAnimator @implementation FullscreenScrollEndAnimator
@synthesize startProgress = _startProgress; @synthesize startProgress = _startProgress;
@synthesize finalProgress = _finalProgress; @synthesize finalProgress = _finalProgress;
@synthesize curve = _curve;
- (instancetype)initWithStartProgress:(CGFloat)startProgress { - (instancetype)initWithStartProgress:(CGFloat)startProgress {
FullscreenScrollEndTimingCurveProvider* curveProvider = // Control points for Material Design CurveEaseOut curve.
[[FullscreenScrollEndTimingCurveProvider alloc] init]; UICubicTimingParameters* timingParams = [[UICubicTimingParameters alloc]
initWithControlPoint1:CGPointMake(0.0, 0.0)
controlPoint2:CGPointMake(0.2, 0.1)];
self = [super initWithDuration:ios::material::kDuration1 self = [super initWithDuration:ios::material::kDuration1
timingParameters:curveProvider]; timingParameters:timingParams];
if (self) { if (self) {
DCHECK_GE(startProgress, 0.0); DCHECK_GE(startProgress, 0.0);
DCHECK_LE(startProgress, 1.0); DCHECK_LE(startProgress, 1.0);
_startProgress = startProgress; _startProgress = startProgress;
_finalProgress = roundf(_startProgress); _finalProgress = roundf(_startProgress);
_curve = curveProvider; _bezier = base::MakeUnique<gfx::CubicBezier>(
timingParams.controlPoint1.x, timingParams.controlPoint1.y,
timingParams.controlPoint2.x, timingParams.controlPoint2.y);
} }
return self; return self;
} }
...@@ -100,8 +48,7 @@ ...@@ -100,8 +48,7 @@
#pragma mark Accessors #pragma mark Accessors
- (CGFloat)currentProgress { - (CGFloat)currentProgress {
CGFloat interpolationFraction = CGFloat interpolationFraction = _bezier->Solve(self.fractionComplete);
self.curve.bezier.Solve(self.fractionComplete);
CGFloat range = self.finalProgress - self.startProgress; CGFloat range = self.finalProgress - self.startProgress;
return self.startProgress + interpolationFraction * range; return self.startProgress + interpolationFraction * range;
} }
......
...@@ -7,6 +7,8 @@ source_set("test") { ...@@ -7,6 +7,8 @@ source_set("test") {
sources = [ sources = [
"fullscreen_model_test_util.h", "fullscreen_model_test_util.h",
"fullscreen_model_test_util.mm", "fullscreen_model_test_util.mm",
"test_fullscreen_controller_observer.h",
"test_fullscreen_controller_observer.mm",
"test_fullscreen_model_observer.h", "test_fullscreen_model_observer.h",
"test_fullscreen_model_observer.mm", "test_fullscreen_model_observer.mm",
] ]
...@@ -14,7 +16,9 @@ source_set("test") { ...@@ -14,7 +16,9 @@ source_set("test") {
configs += [ "//build/config/compiler:enable_arc" ] configs += [ "//build/config/compiler:enable_arc" ]
deps = [ deps = [
"//ios/chrome/browser/ui/fullscreen:new_fullscreen",
"//ios/chrome/browser/ui/fullscreen:new_fullscreen_internal", "//ios/chrome/browser/ui/fullscreen:new_fullscreen_internal",
"//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui",
"//testing/gtest", "//testing/gtest",
] ]
} }
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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_FULLSCREEN_TEST_TEST_FULLSCREEN_CONTROLLER_OBSERVER_H_
#define IOS_CHROME_BROWSER_UI_FULLSCREEN_TEST_TEST_FULLSCREEN_CONTROLLER_OBSERVER_H_
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
// Test version of FullscreenControllerObserver.
class TestFullscreenControllerObserver : public FullscreenControllerObserver {
public:
CGFloat progress() const { return progress_; }
bool enabled() const { return enabled_; }
FullscreenScrollEndAnimator* animator() const { return animator_; }
private:
// FullscreenControllerObserver:
void FullscreenProgressUpdated(FullscreenController* controller,
CGFloat progress) override;
void FullscreenEnabledStateChanged(FullscreenController* controller,
bool enabled) override;
void FullscreenScrollEventEnded(
FullscreenController* controller,
FullscreenScrollEndAnimator* animator) override;
CGFloat progress_ = 0.0;
bool enabled_ = true;
__weak FullscreenScrollEndAnimator* animator_ = nil;
};
#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_TEST_TEST_FULLSCREEN_CONTROLLER_OBSERVER_H_
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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/fullscreen/test/test_fullscreen_controller_observer.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
void TestFullscreenControllerObserver::FullscreenProgressUpdated(
FullscreenController* controller,
CGFloat progress) {
progress_ = progress;
}
void TestFullscreenControllerObserver::FullscreenEnabledStateChanged(
FullscreenController* controller,
bool enabled) {
enabled_ = enabled;
}
void TestFullscreenControllerObserver::FullscreenScrollEventEnded(
FullscreenController* controller,
FullscreenScrollEndAnimator* animator) {
animator_ = animator;
// An animator must have at least one animation block when started, so insert
// a no-op block.
[animator_ addAnimations:^{
}];
}
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