/*
* Copyright 2016-present The Material Motion Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.material.motion;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.TextView;
import com.google.android.indefinite.observable.IndefiniteObservable;
import com.google.android.indefinite.observable.Observer;
import com.google.android.material.motion.MotionObserver.SimpleMotionObserver;
/**
* A MotionObservable is a type of <a href="http://reactivex.io/documentation/observable.html">Observable</a>
* that specializes in motion systems that can be either active or at rest.
* <p>
* Throughout this documentation we will treat the words "observable" and "stream" as synonyms.
*/
public class MotionObservable<T> extends IndefiniteObservable<MotionObserver<T>> {
public MotionObservable(Connector<MotionObserver<T>> connector) {
super(connector);
}
/**
* Subscribes to the IndefiniteObservable and ignores all incoming values.
*
* @see #subscribe(Observer)
*/
public Subscription subscribe() {
return super.subscribe(new SimpleMotionObserver<T>() {
@Override
public void next(T value) {
}
});
}
/**
* A light-weight operator builder. Applies the given operation to the incoming stream.
* <p>
* This is the preferred method for building new operators. This builder can be used to create
* any operator that only needs to modify or block values. All state events are forwarded
* along.
*
* @param operation An operation to apply to each incoming value. The operation must handle
* values of type {@link T} or more general types. For example, an operation that handles {@link
* View}s can be applied to a stream of {@link TextView}s.
* @param <U> The returned stream contains values of this type. The operation must output values
* of this type.
*/
public <U> MotionObservable<U> compose(final Operation<T, U> operation) {
final MotionObservable<T> upstream = MotionObservable.this;
return new MotionObservable<>(new Connector<MotionObserver<U>>() {
@NonNull
@Override
public Disconnector connect(final MotionObserver<U> observer) {
operation.preConnect(observer);
final Subscription subscription = upstream.subscribe(new MotionObserver<T>() {
@Override
public void next(T value) {
operation.next(observer, value);
}
@Override
public void build(MotionBuilder<T> builder, T[] values) {
if (operation instanceof SameTypedMapOperation) {
//noinspection unchecked
((SameTypedMapOperation<T>) operation).build(
(MotionObserver<T>) observer, builder, values);
}
}
});
operation.postConnect(observer);
return new Disconnector() {
@Override
public void disconnect() {
operation.preDisconnect(observer);
subscription.unsubscribe();
operation.postDisconnect(observer);
}
};
}
});
}
public <U> MotionObservable<U> compose(final RawOperation<T, U> operation) {
return operation.compose(this);
}
}