Skip to content
This repository has been archived by the owner on May 15, 2023. It is now read-only.

Commit

Permalink
Merge pull request #130 from material-foundation/develop
Browse files Browse the repository at this point in the history
Move new documentation to stable
  • Loading branch information
miguelandres authored Feb 27, 2017
2 parents e11ecb7 + 403f06b commit ffd14fb
Show file tree
Hide file tree
Showing 11 changed files with 724 additions and 230 deletions.
15 changes: 8 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ language: android
jdk: oraclejdk8

env:
matrix:
- ANDROID_TARGET=android-25
- ANDROID_TARGET=25 BUILD_TOOLS=25.0.0

android:
components:
Expand All @@ -13,32 +12,34 @@ android:
# See https://github.com/travis-ci/travis-ci/issues/6040#issuecomment-219367943 for more
# details.
- platform-tools #latest
- build-tools-25.0.0
- android-25
- "build-tools-$BUILD_TOOLS"
- "android-$ANDROID_TARGET"
- extra-android-support
- extra-android-m2repository
- extra-google-google_play_services
- extra-google-m2repository
- addon-google_apis-google-25
- "addon-google_apis-google-$ANDROID_TARGET"


before_install:
- echo yes | android update sdk --filter extra-android-m2repository --no-ui --force > /dev/null

licenses:
- 'android-sdk-license-.+'
- 'google-gdk-license-.+'

before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -fr $HOME/.gradle/caches/*/plugin-resolution/

cache:
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/

script:
- ./gradlew check jacocoTestReport
- ./gradlew lint check jacocoTestReport
# building remixer_example:assembleRelease will fail explicitly if proguarding is broken.
- ./gradlew remixer_example:assembleRelease

after_success:
- bash <(curl -s https://codecov.io/bash)
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.6.6

- Fix Proguarding issue with bad instructions for onboarding.

# 0.6.5

- Test improvements for Robolectric, styles are now supported
Expand Down
96 changes: 96 additions & 0 deletions CONFIGURE_UI.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
![Remixer](https://cdn.rawgit.com/material-foundation/material-remixer/master/docs/assets/lockup_remixer_icon_horizontal_dark_small.svg)

# Display the Remixer Fragment

You can configure the `RemixerFragment` in the `Activity`'s `onCreate(Bundle)` method, after the call to `RemixerBinder.bind(this)`. You have 3 (not mutually-exclusive) options. You can see examples of how to do it below.

*Note, however, that configuring the UI is optional if you want to exclusively use the Firebase Remote Controller functionality.*

## Attach the Remixer Fragment to a Button
You need to call `RemixerFragment#attachToButton(FragmentActivity, Button)`

Your `Activity.onCreate` may look like this:

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
remixerButton = (Button) findViewById(R.id.button);
RemixerBinder.bind(this);
RemixerFragment.newInstance().attachToButton(this, remixerButton);
}
```

## Attach the Remixer Fragment to a multi-touch gesture
You need to call `RemixerFragment#attachToGesture(FragmentActivity, Direction, int)`

Your `Activity.onCreate` may look like this:

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
RemixerBinder.bind(this);
RemixerFragment.newInstance().attachToGesture(
this,
Direction.UP,
3 /* numberOfFingers */);
}
```

## Attach the Remixer Fragment to a shake
You need to call `RemixerFragment#attachToShake(FragmentActivity, double)` from `onResume()` and call `RemixerFragment#detachFromShake()` from `onPause()`

Your `Activity.onCreate` may look like this:

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
RemixerBinder.bind(this);
remixerFragment = RemixerFragment.newInstance();
}

@Override
protected void onResume() {
super.onResume();
remixerFragment.attachToShake(this, 20.0);
}

@Override
protected void onPause() {
super.onPause();
remixerFragment.detachFromShake();
}
```

## Or combine all of them

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
remixerButton = (Button) findViewById(R.id.button);
RemixerBinder.bind(this);

remixerFragment = RemixerFragment.newInstance();
remixerFragment.attachToGesture(this, Direction.UP, 3);
remixerFragment.attachToButton(this, remixerButton);
}

@Override
protected void onResume() {
super.onResume();
remixerFragment.attachToShake(this, 20.0);
}

@Override
protected void onPause() {
super.onPause();
remixerFragment.detachFromShake();
}
```
76 changes: 76 additions & 0 deletions EXTENDING_REMIXER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Extending Remixer

There are several ways in which you can extend remixer:

- Add a new `DataType`:
- Create a `ValueConverter` for the `DataType`
- Set as default layoutIDs by calling `DataType.setLayoutIdForVariableType(Class<? extends Variable>, int)`
- Register it at `Application.onCreate()` time
- can be done in `RemixerInitialization.initRemixer()` if you're adding it at the Remixer level (forking/contributing)
- **Note**: At the time only forks/contributions can add annotation processing support for new DataTypes. If it proves necessary we'll write extension points for the annotation processor.
- Implement a new `RemixerWidget`
- Optionally, set it as a default Layout Id for a `DataType`/`Variable class` combination by calling `DataType.setLayoutIdForVariableType`. You can do it in `RemixerInitialization.initRemixer()` if forking/contributing.

**Notice that if you plan to use the Firebase Remote Controller functionality, you need to replicate this work in the material-remixer-js and material-remixer-remote-web projects as well**. It is out of scope for this document to explain how to do it in those projects.

## Adding a new DataType

In order to add a new data type to Remixer, you need to construct a static instance of the DataType class...

```java
public static final DataType<RT, ST> MY_NEW_TYPE = new DataType<>(
"myNewType",
RT.class,
ST.class,
new MyNewTypeValueConverter("myNewType"));
```

... and register it as a RemixerType somewhere that only gets called once (preferably during your `Application.onCreate()`)...

```java
public class MyApplication extends Application {

@Override
public void onCreate() {
super.onCreate();
Remixer.registerDataType(MY_NEW_TYPE);
}
}
```

Now let's dissect the first statement, the `new DataType<>(...)`:

1. It has two generic parameters, RT and ST, the RuntimeType and the SerializedType. The former is used for callbacks during runtime, and the latter is used to serialize, store data and (potentially) sync it to Firebase. They can be exactly the same type, and they usually are.
2. It has a unique identifier string, in the example it's "myNewType". It can be whatever you want but current identifier strings are "boolean", "color", "number" and "string".
3. You need to write a subclass of `ValueConverter` which converts between the RuntimeType and the SerializedType and performs other serialization-related tasks.


Now you can use it with any of the variable classes using the appropriate Builder. Just make sure to call `setDataType(MY_DATA_TYPE)` and you're done.

## Add a new Variable subclass

Variable subclasses represent constraints on what values the variable can take.

1. Create a subclass of Variable.
2. Override its `checkValue(T)` method.
3. Override its `getSerializableConstraints()` method with a new constant constraint string that is unique to this class.
4. Add new fields to `StoredVariable` representing new data required to represent the new variable subclass.
5. Make sure you update `ValueConverter`'s `fromVariable(Variable<?>)`, `serialize(StoredVariable<SerializableType>)` and `deserialize(JsonElement)` methods to match the new fields.

## Adding new annotation support

If you add a new type or variable you may want to make it easier to use by adding annotation support. This is easy if you are forking or contributing to the android remixer repository, but otherwise we do not currently offer a way to extend the annnotation processor. We may if this becomes a problem down the line.

1. Subclass `MethodAnnotation` to handle your new annotation classes.
2. Add a new enum item per new annotation you're supporting to `SupportedMethodAnnotation`
3. Add lots of tests, these errors are hard to debug, so please do your best to keep coverage high.

## Implement a new RemixerWidget

**Note:** Remixer relies on inflating widgets by layout id, so these cannot be pure-java, they need to have a layout resource associated with them.

1. Write a new class that extends `android.view.ViewGroup` (usually either `LinearLayout` or `RelativeLayout`) and implements `RemixerWidget`
2. Add a new layout resource whose element is of the class you just created.
3. Optionally, set it as a default Layout Id for a `DataType`/`Variable class` combination by calling `DataType.setLayoutIdForVariableType(Class<? extends Variable>, int)`. You can do it in `RemixerInitialization.initRemixer()` if forking/contributing.

Even if you do not set it as a default layout anywhere, you can still force to use it by setting the layoutId property on a variable.
111 changes: 111 additions & 0 deletions GETTING_STARTED.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
![Remixer](https://cdn.rawgit.com/material-foundation/material-remixer/master/docs/assets/lockup_remixer_icon_horizontal_dark_small.svg)

# Getting started

__Disclaimer:__ Remixer still hasn't reached a stage that we consider is stable enough to commit to the current status of the API, it will be evolving quickly and we may commit breaking changes every once in a while. _That being said_, we would love to have you try it out and tell us what you think is missing and what you'd like us to focus on.

You can read our [javadoc for the current release (0.6.6)](https://jitpack.io/com/github/material-foundation/material-remixer-android/remixer/0.6.6/javadoc/index.html) and the [javadoc for HEAD](https://jitpack.io/com/github/material-foundation/material-remixer-android/remixer/develop-SNAPSHOT/javadoc/index.html) generated by jitpack.

## Set up dependencies

Using gradle it's super easy to start using Remixer following these instructions.

In your main build.gradle file make sure you have the following dependencies and repositories set up:

```gradle
buildscript {
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
```

And in your modules, apply the `android-apt` plugin and add the remixer dependencies:
```gradle
apply plugin: 'android-apt'
dependencies {
compile 'com.github.material-foundation.material-remixer-android:remixer:0.6.6'
provided 'com.github.material-foundation.material-remixer-android:remixer_annotation:0.6.6'
}
```

Notice the dependency on `remixer_annotation` is a `provided` clause instead of `compile`, this is on purpose as this is not a regular dependency but a compiler plugin.

Once you start depending on Remixer, your build will fail if no `google-services.json` exists on your app module. This is because Remixer has the option of using firebase to store and sync values, and whether you use it or not the build system looks for that file. It can be an empty file or the one we provide in `remixer_example/src/main/google-services.json`.

## Initialize remixer

1. Subclass the `android.app.Application`.
2. [Declare it in your Android Manifest](https://developer.android.com/guide/topics/manifest/application-element.html#nm).
3. Call the `RemixerInitialization#initRemixer(Application)` method.
4. Set a synchronization mechanism for Remixer (you have a few options):
- `com.google.android.libraries.remixer.sync.LocalValueSyncing`, this is the default (you don't need to set it if this is what you want), it doesn't persist any values but makes sure values sync across different contexts (Activities).
- `com.google.android.libraries.remixer.storage.LocalStorage`, this stores values locally in a SharedPreferences file.
- `com.google.android.libraries.remixer.storage.FirebaseRemoteControllerSyncer`, this syncs values to and from a firebase instance to use it as a remote controller. **This functionality is not complete yet**

For example:

```java
import android.app.Application;
import com.google.android.libraries.remixer.Remixer;
import com.google.android.libraries.remixer.storage.LocalStorage;
import com.google.android.libraries.remixer.ui.RemixerInitialization;

class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
RemixerInitialization.initRemixer(this);
Remixer.getInstance().setSynchronizationMechanism(new LocalStorage(getApplicationContext()));
}
}
```

## Define Variables

You can define variables in an activty by writing methods that take one argument of the correct type and annotate them. The methods contain your logic to handle changes to these variables (update the UI accordingly).

You can rest assured those methods will run in the main UI thread.

There are a few very simple examples here, but you should look at the [example](https://github.com/material-foundation/material-remixer-android/blob/develop/remixer_example/src/main/java/com/google/android/apps/remixer/MainActivity.java) [activities](https://github.com/material-foundation/material-remixer-android/blob/develop/remixer_example/src/main/java/com/google/android/apps/remixer/BoxActivity.java) and [documentation for these annotations](https://github.com/material-foundation/material-remixer-android/tree/develop/remixer_core/src/main/java/com/google/android/libraries/remixer/annotation) for more information.

For example:

```java
@RangeVariableMethod(minValue = 15, maxValue = 70, initialValue = 20)
public void setFontSize(Float fontSize) {
titleText.setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
}
```

Additionally, you need to add `RemixerBinder.bind(this)` at the end of your activity's `onCreate(Bundle)`.

```java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//...
RemixerBinder.bind(this);
}
```

## Display the Remixer Fragment

You can configure the `RemixerFragment` in the `Activity`'s `onCreate(Bundle)` method, after the call to `RemixerBinder.bind(this)`. You have 3 (not mutually-exclusive) options:

1. [Attach the RemixerFragment to a button click](CONFIGURE_UI.md#attach-the-remixer-fragment-to-a-button), `RemixerFragment#attachToButton(FragmentActivity, Button)`
2. [Attach the RemixerFragment to a multi-touch gesture](CONFIGURE_UI.md#attach-the-remixer-fragment-to-a-multi-touch-gesture), `RemixerFragment#attachToButton(FragmentActivity, Button)`
3. [Attach the RemixerFragment to a ShakeListener](CONFIGURE_UI.md#attach-the-remixer-fragment-to-a-shake), `RemixerFragment#attachToShake(FragmentActivity, double)`. *In order to conserve battery, you must call `attachToShake` from `onResume` and call `detachFromShake` from `onPause`*

Detailed examples can be found on the [Configure the UI](CONFIGURE_UI.md) page.


_You may not want to use the `RemixerFragment` in case you only want to use a FirebaseRemoteController. Adding a RemixerFragment does affect the UI you may be playing with, so it may be desirable not to use it and tweak remotely instead._
Loading

0 comments on commit ffd14fb

Please sign in to comment.