Skip to content
This repository has been archived by the owner on Aug 13, 2021. It is now read-only.

Commit

Permalink
Implement MotionObservable in android.
Browse files Browse the repository at this point in the history
Reviewers: featherless, O2 Material Motion, O6 Material Motion Android platform reviewers

Reviewed By: featherless, O2 Material Motion, O6 Material Motion Android platform reviewers

Subscribers: featherless

Tags: #material_motion

Differential Revision: http://codereview.cc/D2150
  • Loading branch information
Mark Wei committed Dec 7, 2016
1 parent 7cde681 commit c4c5e45
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 31 deletions.
1 change: 1 addition & 0 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ android {

dependencies {
// If you are developing any dependencies locally, also list them in local.dependencies.
compile 'com.github.material-motion:indefinite-observable-android:1.0.0'

testCompile 'com.google.truth:truth:0.28'
testCompile 'junit:junit:4.12'
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.streams;

import android.support.annotation.IntDef;

import com.google.android.material.motion.observable.IndefiniteObservable;
import com.google.android.material.motion.observable.Observer;
import com.google.android.material.motion.streams.MotionObservable.MotionObserver;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* 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.
*
* @see <a href="https://material-motion.github.io/material-motion/starmap/specifications/streams/MotionObservable">The
* motion observable specification</a>
*/
public class MotionObservable<T> extends IndefiniteObservable<MotionObserver<T>> {

/**
* The stream is at rest.
*/
public static final int AT_REST = 0;

/**
* The stream is currently active.
*/
public static final int ACTIVE = 1;

public MotionObservable(Subscriber<MotionObserver<T>> subscriber) {
super(subscriber);
}

/**
* The possible states that a stream can be in.
* <p>
* What "active" means is stream-dependant. The stream is active if you can answer yes to any of
* the following questions: <ul> <li>Is my animation currently animating?</li> <li>Is my
* physical simulation still moving?</li> <li>Is my gesture recognizer in the .began or .changed
* state?</li> </ul> Momentary events such as taps may emit {@link #ACTIVE} immediately followed
* by {@link #AT_REST}.
*/
@IntDef({AT_REST, ACTIVE})
@Retention(RetentionPolicy.SOURCE)
public @interface MotionState {

}

/**
* An observer with an additional {@link #state(int)} method.
*/
public interface MotionObserver<T> extends Observer<T> {

@Override
void next(T value);

/**
* A method to handle new state values from upstream.
*/
void state(@MotionState int state);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,112 @@
*/
package com.google.android.material.motion.streams.sample;

import com.google.android.material.motion.streams.Library;

import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.google.android.material.motion.observable.IndefiniteObservable.Subscriber;
import com.google.android.material.motion.observable.IndefiniteObservable.Subscription;
import com.google.android.material.motion.observable.IndefiniteObservable.Unsubscriber;
import com.google.android.material.motion.streams.MotionObservable;
import com.google.android.material.motion.streams.MotionObservable.MotionObserver;
import com.google.android.material.motion.streams.MotionObservable.MotionState;

import static com.google.android.material.motion.streams.MotionObservable.ACTIVE;
import static com.google.android.material.motion.streams.MotionObservable.AT_REST;

/**
* Streams for Android sample Activity.
*/
public class MainActivity extends AppCompatActivity {

private static final String[] values = new String[]{
"foo", "bar", "baz", "qux"
};

private MotionObserver<String> callback;
private int index = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.main_activity);

TextView text = (TextView) findViewById(R.id.text);
text.setText(Library.LIBRARY_NAME);
final TextView text = (TextView) findViewById(R.id.text);
Button nextButton = (Button) findViewById(R.id.next_button);
Button unsubscribeButton = (Button) findViewById(R.id.unsubscribe_button);

MotionObservable<String> observable = new MotionObservable<>(
new Subscriber<MotionObserver<String>>() {
@Nullable
@Override
public Unsubscriber subscribe(MotionObserver<String> observer) {
registerButtonCallback(observer);
return new Unsubscriber() {
@Override
public void unsubscribe() {
unregisterButtonCallback();
}
};
}
});

final Subscription subscription = observable.subscribe(new MotionObserver<String>() {
@Override
public void next(String value) {
text.setText(value);
}

@Override
public void state(@MotionState int state) {
switch (state) {
case AT_REST:
text.setTextColor(Color.BLACK);
break;
case ACTIVE:
text.setTextColor(Color.RED);
break;
}
}
});

nextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (callback != null) {
if (index < values.length) {
callback.next(values[index]);
}

if (index + 1 < values.length) {
callback.state(ACTIVE);
} else {
callback.state(AT_REST);
}

index++;
}
}
});

unsubscribeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
subscription.unsubscribe();
}
});
}

private void registerButtonCallback(MotionObserver<String> observer) {
callback = observer;
}

private void unregisterButtonCallback() {
callback = null;
}
}
20 changes: 17 additions & 3 deletions sample/src/main/res/layout/main_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,26 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello, World!"/>
</FrameLayout>

<Button
android:id="@+id/next_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Next"/>

<Button
android:id="@+id/unsubscribe_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Unsubscribe"/>
</LinearLayout>

0 comments on commit c4c5e45

Please sign in to comment.