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") {
sources = [
"fullscreen_controller.mm",
"fullscreen_controller_factory.mm",
"fullscreen_mediator.h",
"fullscreen_mediator.mm",
"fullscreen_model.h",
"fullscreen_model.mm",
"fullscreen_model_observer.h",
......@@ -88,6 +90,7 @@ source_set("new_fullscreen_ui") {
source_set("new_unit_tests") {
testonly = true
sources = [
"fullscreen_mediator_unittest.mm",
"fullscreen_model_unittest.mm",
"fullscreen_ui_updater_unittest.mm",
"fullscreen_web_state_list_observer_unittest.mm",
......
......@@ -14,6 +14,7 @@
@class ChromeBroadcaster;
@class ChromeBroadcastOberverBridge;
class FullscreenControllerObserver;
class FullscreenMediator;
class FullscreenModel;
class FullscreenWebStateListObserver;
......@@ -59,6 +60,8 @@ class FullscreenController : public KeyedService {
std::unique_ptr<FullscreenModel> model_;
// The bridge used to forward brodcasted UI to |model_|.
__strong ChromeBroadcastOberverBridge* bridge_ = nil;
// Object that manages sending signals to FullscreenControllerObservers.
std::unique_ptr<FullscreenMediator> mediator_;
// A WebStateListObserver that updates |model_| for WebStateList changes.
std::unique_ptr<FullscreenWebStateListObserver> web_state_list_observer_;
......
......@@ -7,6 +7,7 @@
#include "base/memory/ptr_util.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/fullscreen/fullscreen_mediator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_model.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_web_state_list_observer.h"
......@@ -17,8 +18,9 @@
FullscreenController::FullscreenController()
: broadcaster_([[ChromeBroadcaster alloc] init]),
model_(base::MakeUnique<FullscreenModel>()),
bridge_([[ChromeBroadcastOberverBridge alloc]
initWithObserver:model_.get()]) {
bridge_(
[[ChromeBroadcastOberverBridge alloc] initWithObserver:model_.get()]),
mediator_(base::MakeUnique<FullscreenMediator>(this, model_.get())) {
DCHECK(broadcaster_);
[broadcaster_ addObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)];
......@@ -33,14 +35,12 @@ FullscreenController::FullscreenController()
FullscreenController::~FullscreenController() = default;
void FullscreenController::AddObserver(FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep
// track of observers.
mediator_->AddObserver(observer);
}
void FullscreenController::RemoveObserver(
FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep
// track of observers.
mediator_->RemoveObserver(observer);
}
bool FullscreenController::IsEnabled() const {
......@@ -56,6 +56,7 @@ void FullscreenController::DecrementDisabledCounter() {
}
void FullscreenController::Shutdown() {
mediator_->Disconnect();
[broadcaster_ removeObserver:bridge_
forSelector:@selector(broadcastContentScrollOffset:)];
[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 @@
#error "This file requires ARC support."
#endif
@interface FullscreenScrollEndTimingCurveProvider
: NSObject<UITimingCurveProvider> {
@interface FullscreenScrollEndAnimator () {
// The bezier backing the timing curve.
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
@implementation FullscreenScrollEndAnimator
@synthesize startProgress = _startProgress;
@synthesize finalProgress = _finalProgress;
@synthesize curve = _curve;
- (instancetype)initWithStartProgress:(CGFloat)startProgress {
FullscreenScrollEndTimingCurveProvider* curveProvider =
[[FullscreenScrollEndTimingCurveProvider alloc] init];
// Control points for Material Design CurveEaseOut curve.
UICubicTimingParameters* timingParams = [[UICubicTimingParameters alloc]
initWithControlPoint1:CGPointMake(0.0, 0.0)
controlPoint2:CGPointMake(0.2, 0.1)];
self = [super initWithDuration:ios::material::kDuration1
timingParameters:curveProvider];
timingParameters:timingParams];
if (self) {
DCHECK_GE(startProgress, 0.0);
DCHECK_LE(startProgress, 1.0);
_startProgress = 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;
}
......@@ -100,8 +48,7 @@
#pragma mark Accessors
- (CGFloat)currentProgress {
CGFloat interpolationFraction =
self.curve.bezier.Solve(self.fractionComplete);
CGFloat interpolationFraction = _bezier->Solve(self.fractionComplete);
CGFloat range = self.finalProgress - self.startProgress;
return self.startProgress + interpolationFraction * range;
}
......
......@@ -7,6 +7,8 @@ source_set("test") {
sources = [
"fullscreen_model_test_util.h",
"fullscreen_model_test_util.mm",
"test_fullscreen_controller_observer.h",
"test_fullscreen_controller_observer.mm",
"test_fullscreen_model_observer.h",
"test_fullscreen_model_observer.mm",
]
......@@ -14,7 +16,9 @@ source_set("test") {
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
"//ios/chrome/browser/ui/fullscreen:new_fullscreen",
"//ios/chrome/browser/ui/fullscreen:new_fullscreen_internal",
"//ios/chrome/browser/ui/fullscreen:new_fullscreen_ui",
"//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