Commit 283aee4e authored by Kurt Horimoto's avatar Kurt Horimoto Committed by Commit Bot

[iOS] Add preliminary fullscreen clases.

This CL adds some base classes around which Fullscreen implementation
will be built.  There is no functionality yet; other classes must be added
and setup by FullscreenController.  Classes added:
- FullscreenController and its observer class
- FullscreenUIElement and its updater
- FullscreenScrollEndAnimator
- ScopedFullscreenDisabler

Bug: 778016
Cq-Include-Trybots: master.tryserver.chromium.mac:ios-simulator-cronet;master.tryserver.chromium.mac:ios-simulator-full-configs
Change-Id: I11439513f4e52515bfee382ccd41cfe531c931a3
Reviewed-on: https://chromium-review.googlesource.com/773473Reviewed-by: default avatarKurt Horimoto <kkhorimoto@chromium.org>
Reviewed-by: default avatarMark Cogan <marq@chromium.org>
Commit-Queue: Kurt Horimoto <kkhorimoto@chromium.org>
Cr-Commit-Position: refs/heads/master@{#517320}
parent d8cee53e
...@@ -15,6 +15,83 @@ source_set("fullscreen") { ...@@ -15,6 +15,83 @@ source_set("fullscreen") {
] ]
} }
source_set("new_fullscreen") {
sources = [
"fullscreen_controller.h",
"fullscreen_controller_observer.h",
"fullscreen_ui_updater.h",
"scoped_fullscreen_disabler.h",
]
configs += [ "//build/config/compiler:enable_arc" ]
allow_circular_includes_from = [ ":new_fullscreen_internal" ]
deps = [
":new_fullscreen_internal",
":new_fullscreen_ui",
"//base",
"//ios/chrome/browser/ui/browser_list",
"//ios/chrome/browser/web_state_list",
]
}
source_set("new_fullscreen_internal") {
sources = [
"fullscreen_controller.mm",
"fullscreen_ui_updater.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
":new_fullscreen_ui",
"//base",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/broadcaster",
"//ios/chrome/browser/ui/browser_list",
"//ios/chrome/browser/web_state_list",
"//ios/web",
]
}
source_set("new_fullscreen_ui") {
sources = [
"fullscreen_scroll_end_animator.h",
"fullscreen_scroll_end_animator.mm",
"fullscreen_ui_element.h",
]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
"//base",
"//ios/chrome/common:timing",
"//ui/gfx/geometry",
]
}
source_set("new_unit_tests") {
testonly = true
sources = [
"fullscreen_ui_updater_unittest.mm",
]
configs += [ "//build/config/compiler:enable_arc" ]
deps = [
":new_fullscreen",
":new_fullscreen_internal",
":new_fullscreen_ui",
"//ios/chrome/browser/ui:ui_util",
"//ios/chrome/browser/ui/broadcaster",
"//ios/web",
"//ios/web/public",
"//ios/web/public/test/fakes",
"//testing/gtest",
]
}
source_set("legacy_fullscreen") { source_set("legacy_fullscreen") {
sources = [ sources = [
"legacy_fullscreen_controller.h", "legacy_fullscreen_controller.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.
#ifndef IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_H_
#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_H_
#include <memory>
#include "base/macros.h"
class FullscreenControllerObserver;
// An object that observes scrolling events in the main content area and
// calculates how much of the toolbar should be visible as a result. When the
// user scrolls down the screen, the toolbar should be hidden to allow more of
// the page's content to be visible.
class FullscreenController {
public:
explicit FullscreenController();
~FullscreenController();
// Adds and removes FullscreenControllerObservers.
void AddObserver(FullscreenControllerObserver* observer);
void RemoveObserver(FullscreenControllerObserver* observer);
// FullscreenController can be disabled when a feature requires that the
// toolbar be fully visible. Since there are multiple reasons fullscreen
// might need to be disabled, this state is represented by a counter rather
// than a single bool. When a feature needs the toolbar to be visible, it
// calls IncrementDisabledCounter(). After that feature no longer requires
// the toolbar, it calls DecrementDisabledCounter(). IsEnabled() returns
// true when the counter is equal to zero. ScopedFullscreenDisabler can be
// used to tie a disabled counter to an object's lifetime.
bool IsEnabled() const;
void IncrementDisabledCounter();
void DecrementDisabledCounter();
private:
DISALLOW_COPY_AND_ASSIGN(FullscreenController);
};
#endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_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_controller.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
FullscreenController::FullscreenController() {}
FullscreenController::~FullscreenController() {}
void FullscreenController::AddObserver(FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep
// track of observers.
}
void FullscreenController::RemoveObserver(
FullscreenControllerObserver* observer) {
// TODO(crbug.com/785671): Use FullscreenControllerObserverManager to keep
// track of observers.
}
bool FullscreenController::IsEnabled() const {
// TODO(crbug.com/785665): Use FullscreenModel to track enabled state.
return false;
}
void FullscreenController::IncrementDisabledCounter() {
// TODO(crbug.com/785665): Use FullscreenModel to track enabled state.
}
void FullscreenController::DecrementDisabledCounter() {
// TODO(crbug.com/785665): Use FullscreenModel to track enabled state.
}
// 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_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_OBSERVER_H_
#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_CONTROLLER_OBSERVER_H_
#include <CoreGraphics/CoreGraphics.h>
#include "base/macros.h"
class FullscreenController;
@class FullscreenScrollEndAnimator;
// Interface for listening to fullscreen state.
class FullscreenControllerObserver {
public:
FullscreenControllerObserver() = default;
virtual ~FullscreenControllerObserver() = default;
// Invoked after a scrolling event has caused |controller| to calculate
// |progress|. A |progress| value of 1.0 denotes that the toolbar should be
// completely visible, while a |progress| value of 0.0 denotes that the
// toolbar should be competely hidden.
virtual void FullscreenProgressUpdated(FullscreenController* controller,
CGFloat progress) {}
// Invoked with |controller| is enabled or disabled.
virtual void FullscreenEnabledStateChanged(FullscreenController* controller,
bool enabled) {}
// Invoked when a scroll event being observed by |controller| has ended.
// Observers can add animations to |animator|.
virtual void FullscreenScrollEventEnded(
FullscreenController* controller,
FullscreenScrollEndAnimator* animator) {}
private:
DISALLOW_COPY_AND_ASSIGN(FullscreenControllerObserver);
};
#endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_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.
#ifndef IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_H_
#import <UIKit/UIKit.h>
#if defined(__IPHONE_10_0) && (__IPHONE_OS_VERSION_MIN_ALLOWED >= __IPHONE_10_0)
// When a scroll event ends, the toolbar should be either completely hidden or
// completely visible. If a scroll ends and the toolbar is partly visible, this
// animator will be provided to UI elements to animate its state to a hidden or
// visible state.
@interface FullscreenScrollEndAnimator : UIViewPropertyAnimator
// The progress value at the start of the animation.
@property(nonatomic, readonly) CGFloat startProgress;
// The final calculated fullscreen value.
@property(nonatomic, readonly) CGFloat finalProgress;
// The current progress value. This is the fullscreen progress value
// interpolated between |startProgress| and |finalProgress| using the timing
// curve and the fraction complete of the animation.
@property(nonatomic, readonly) CGFloat currentProgress;
// Designated initializer.
- (instancetype)initWithStartProgress:(CGFloat)startProgress
NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithDuration:(NSTimeInterval)duration
timingParameters:(id<UITimingCurveProvider>)parameters
NS_UNAVAILABLE;
@end
#else
// Dummy object.
// TODO(crbug.com/768876): Remove this class and the #if guards once iOS9
// support is dropped.
@interface FullscreenScrollEndAnimator : NSObject
@end
#endif // __IPHONE_10_0
#endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_SCROLL_END_ANIMATOR_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_scroll_end_animator.h"
#include <math.h>
#include <algorithm>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#import "ios/chrome/common/material_timing.h"
#include "ui/gfx/geometry/cubic_bezier.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#if defined(__IPHONE_10_0) && (__IPHONE_OS_VERSION_MIN_ALLOWED >= __IPHONE_10_0)
@interface FullscreenScrollEndTimingCurveProvider
: NSObject<UITimingCurveProvider> {
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];
self = [super initWithDuration:ios::material::kDuration1
timingParameters:curveProvider];
if (self) {
DCHECK_GE(startProgress, 0.0);
DCHECK_LE(startProgress, 1.0);
_startProgress = startProgress;
_finalProgress = roundf(_startProgress);
_curve = curveProvider;
}
return self;
}
#pragma mark Accessors
- (CGFloat)currentProgress {
CGFloat interpolationFraction =
self.curve.bezier.Solve(self.fractionComplete);
CGFloat range = self.finalProgress - self.startProgress;
return self.startProgress + interpolationFraction * range;
}
#pragma mark UIViewPropertyAnimator
- (BOOL)isInterruptible {
return YES;
}
@end
#else
@implementation FullscreenScrollEndAnimator
@end
#endif // __IPHONE_10_0
// 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_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_ELEMENT_H_
#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_ELEMENT_H_
#import <Foundation/Foundation.h>
@class FullscreenScrollEndAnimator;
// UI elements that need to react to Fullscreen events should conform to this
// protocol to react to changes in Fullscreen state.
@protocol FullscreenUIElement<NSObject>
// Tells the UI to update its state for |progress|. A fullscreen |progress|
// value denotes that the toolbar should be completely visible, and a |progress|
// value of 0.0 denotes that the toolbar should be completely hidden.
- (void)updateForFullscreenProgress:(CGFloat)progress;
// Tells the UI that fullscreen is enabled or disabled. When disabled, the UI
// should immediately be updated to the state corresponding with a progress
// value of 1.0.
- (void)updateForFullscreenEnabled:(BOOL)enabled;
// Called when a fullscreen scroll event has finished. UI elements that react
// to fullscreen events can configure |animator| with animations.
- (void)finishFullscreenScrollWithAnimator:
(FullscreenScrollEndAnimator*)animator;
@end
#endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_ELEMENT_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.
#ifndef IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_H_
#define IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_H_
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_observer.h"
@protocol FullscreenUIElement;
// Observer that updates UI elements for FullscreenController.
class FullscreenUIUpdater : public FullscreenControllerObserver {
public:
// Contructor for an observer that updates |ui_element|. |ui_element| is not
// retained.
explicit FullscreenUIUpdater(id<FullscreenUIElement> ui_element);
private:
// FullscreenControllerObserver:
void FullscreenProgressUpdated(FullscreenController* controller,
CGFloat progress) override;
void FullscreenEnabledStateChanged(FullscreenController* controller,
bool enabled) override;
void FullscreenScrollEventEnded(
FullscreenController* controller,
FullscreenScrollEndAnimator* animator) override;
// The UI element being updated by this observer.
__weak id<FullscreenUIElement> ui_element_;
};
#endif // IOS_CLEAN_CHROME_BROWSER_UI_FULLSCREEN_FULLSCREEN_UI_UPDATER_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_ui_updater.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
FullscreenUIUpdater::FullscreenUIUpdater(id<FullscreenUIElement> ui_element)
: ui_element_(ui_element) {}
void FullscreenUIUpdater::FullscreenProgressUpdated(
FullscreenController* controller,
CGFloat progress) {
[ui_element_ updateForFullscreenProgress:progress];
}
void FullscreenUIUpdater::FullscreenEnabledStateChanged(
FullscreenController* controller,
bool enabled) {
[ui_element_ updateForFullscreenEnabled:enabled];
}
void FullscreenUIUpdater::FullscreenScrollEventEnded(
FullscreenController* controller,
FullscreenScrollEndAnimator* animator) {
[ui_element_ finishFullscreenScrollWithAnimator:animator];
}
// 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_ui_updater.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_scroll_end_animator.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_element.h"
#include "ios/chrome/browser/ui/ui_util.h"
#include "testing/platform_test.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#pragma mark - TestFullscreenUIElement
@interface TestFullscreenUIElement : NSObject<FullscreenUIElement>
// The values that are passed to the UI element through the UI updater.
@property(nonatomic, readonly) CGFloat progress;
@property(nonatomic, readonly, getter=isEnabled) BOOL enabled;
@property(nonatomic, readonly) FullscreenScrollEndAnimator* animator;
@end
@implementation TestFullscreenUIElement
@synthesize progress = _progress;
@synthesize enabled = _enabled;
@synthesize animator = _animator;
- (void)updateForFullscreenProgress:(CGFloat)progress {
_progress = progress;
}
- (void)updateForFullscreenEnabled:(BOOL)enabled {
_enabled = enabled;
}
- (void)finishFullscreenScrollWithAnimator:
(FullscreenScrollEndAnimator*)animator {
_animator = animator;
}
@end
#pragma mark - FullscreenUIUpdaterTest
// Test fixture for FullscreenBroadcastForwarder.
class FullscreenUIUpdaterTest : public PlatformTest {
public:
FullscreenUIUpdaterTest()
: PlatformTest(),
element_([[TestFullscreenUIElement alloc] init]),
updater_(element_) {}
TestFullscreenUIElement* element() { return element_; }
FullscreenControllerObserver* observer() { return &updater_; }
private:
__strong TestFullscreenUIElement* element_;
FullscreenUIUpdater updater_;
};
// Tests that the updater correctly changes the UI element's progress value.
TEST_F(FullscreenUIUpdaterTest, Progress) {
ASSERT_TRUE(AreCGFloatsEqual(element().progress, 0.0));
const CGFloat kProgress = 0.5;
observer()->FullscreenProgressUpdated(nullptr, kProgress);
EXPECT_TRUE(AreCGFloatsEqual(element().progress, kProgress));
}
// Tests that the updater correctly changes the UI element's enabled state.
TEST_F(FullscreenUIUpdaterTest, EnabledDisabled) {
ASSERT_FALSE(element().enabled);
observer()->FullscreenEnabledStateChanged(nullptr, true);
EXPECT_TRUE(element().enabled);
observer()->FullscreenEnabledStateChanged(nullptr, false);
EXPECT_FALSE(element().enabled);
}
// Tests that the updater sends the animator to the UI element.
TEST_F(FullscreenUIUpdaterTest, ScrollEnd) {
ASSERT_FALSE(element().animator);
FullscreenScrollEndAnimator* const kAnimator =
[[FullscreenScrollEndAnimator alloc] init];
observer()->FullscreenScrollEventEnded(nullptr, kAnimator);
EXPECT_EQ(element().animator, kAnimator);
}
// 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_SCOPED_FULLSCREEN_DISABLER_H_
#define IOS_CHROME_BROWSER_UI_FULLSCREEN_SCOPED_FULLSCREEN_DISABLER_H_
#include "base/logging.h"
#include "base/macros.h"
#import "ios/chrome/browser/ui/fullscreen/fullscreen_controller.h"
// A helper object that increments FullscrenController's disabled counter for
// its entire lifetime.
class ScopedFullscreenDisabler {
public:
explicit ScopedFullscreenDisabler(FullscreenController* controller)
: controller_(controller) {
DCHECK(controller_);
controller_->IncrementDisabledCounter();
}
~ScopedFullscreenDisabler() { controller_->DecrementDisabledCounter(); }
private:
// The FullscreenController being disabled by this object.
FullscreenController* controller_;
DISALLOW_COPY_AND_ASSIGN(ScopedFullscreenDisabler);
};
#endif // IOS_CHROME_BROWSER_UI_FULLSCREEN_SCOPED_FULLSCREEN_DISABLER_H_
...@@ -189,6 +189,7 @@ test("ios_chrome_unittests") { ...@@ -189,6 +189,7 @@ test("ios_chrome_unittests") {
"//ios/chrome/browser/ui/fancy_ui:unit_tests", "//ios/chrome/browser/ui/fancy_ui:unit_tests",
"//ios/chrome/browser/ui/first_run:unit_tests", "//ios/chrome/browser/ui/first_run:unit_tests",
"//ios/chrome/browser/ui/fullscreen:legacy_unit_tests", "//ios/chrome/browser/ui/fullscreen:legacy_unit_tests",
"//ios/chrome/browser/ui/fullscreen:new_unit_tests",
"//ios/chrome/browser/ui/history:unit_tests", "//ios/chrome/browser/ui/history:unit_tests",
"//ios/chrome/browser/ui/history_popup:unit_tests", "//ios/chrome/browser/ui/history_popup:unit_tests",
"//ios/chrome/browser/ui/icons:unit_tests", "//ios/chrome/browser/ui/icons:unit_tests",
......
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