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

Commit

Permalink
Merge branch 'release-candidate' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
Miguel Yanez Barreto committed Jan 6, 2017
2 parents e7a99e9 + efe0933 commit 62d8db3
Show file tree
Hide file tree
Showing 121 changed files with 1,603 additions and 1,496 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# 0.6.0

## Breaking changes

- Numbers are now backed by floats. So if you're using `RangeVariableMethod` or `IntegerListVariableMethod`, the callbacks will take `Float` instead of `Integer`
- Furthermore, `IntegerListVariableMethod` has been split into `NumberListVariableMethod` and `ColorListVariableMethod`.
- Colors are still backed by Integers
- No more base type changes are expected, but sorry about this one, this had to be done and it had been a while under work.
- Triggers are gone.
47 changes: 22 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ The project is defined as a gradle project with submodules.
* remixer_ui: The code that shows remixes in the UI.
* main
* `com.google.android.libraries.remixer.ui.view` is the code to display the UI as a BottomSheetFragmentDialog
* `com.google.android.libraries.remixer.ui.widget` is a family of widgets that can display each individual Remixer item (variable or trigger).
* `com.google.android.libraries.remixer.ui.widget.RemixerItemWidget` is an Interface to implement such widgets. Necessary if you want to provide different widgets.
* `com.google.android.libraries.remixer.ui.widget` is a family of widgets that can display each individual Remixer items (variables).
* `com.google.android.libraries.remixer.ui.widget.RemixerWidget` is an Interface to implement such widgets. Necessary if you want to provide different widgets.
* `com.google.android.libraries.remixer.ui.RemixerCallbacks` is an implementation of `Application.ActivityLifecycleCallbacks` that clears up callbacks once the corresponding activity is destroyed so it doesn't leak. It needs to be registered in the `Application.onCreate()` method.
* tests: JUnit/Robolectric tests.
* remixer_annotation: An annotation processor to make it easier to add remixes to your code.
Expand All @@ -33,6 +33,8 @@ The project is defined as a gradle project with submodules.

__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 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.0)](https://jitpack.io/com/github/material-foundation/material-remixer-android/remixer/0.6.0/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.
Expand All @@ -59,7 +61,7 @@ And in your modules, apply the `android-apt` plugin and add the remixer dependen
apply plugin: 'android-apt'
dependencies {
compile 'com.github.material-foundation.material-remixer-android:remixer:0.5.2'
compile 'com.github.material-foundation.material-remixer-android:remixer:0.6.0'
}
```

Expand All @@ -68,25 +70,33 @@ Notice the dependency on `remixer_annotation` is a `provided` clause instead of
### Global remixer set up
If you have not subclassed the application class it is recommended you do it since this is a one-time global initialization.

In your application class you need to call the Remixer initialization method.
In your application class you need to call the Remixer initialization method. Remember this application class MUST be [declared in your Android Manifest](https://developer.android.com/guide/topics/manifest/application-element.html#nm).

```java
class MyApplication extends android.app.Application {
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(Remixer.getInstance(), this);
Remixer.getInstance().setSynchronizationMechanism(new LocalStorage(getApplicationContext()));
}
}
```

The line that calls `setSynchronizationMechanism` makes Remixer values persistent using SharedPreferences. If you would not like to persist values remove this line.

### How to use it in an activity

__Only in the activities where you're using remixer__

You need to add a few lines at the end of your `Activity.onCreate()`

1. `RemixerBinder.bind(this);` creates, initializes and sets up all the Variables and trigger you define in this activity.
1. `RemixerBinder.bind(this);` creates, initializes and sets up all the Variables you define in this activity.
2. `RemixerFragment remixerFragment = RemixerFragment.newInstance();` creates the fragment that will be shown when remixer is invoked, then you need at least one of the following:
- A variation of `remixerFragment.attachToGesture(this, Direction.UP, 3);`, this example ties showing the Remixer Fragment on a 3-finger swipe up.
- `remixerFragment.attachToButton(this, someButtonObject);`, this makes the OnClickListener for a button open the Remixer fragment.
Expand All @@ -111,7 +121,7 @@ In order to define variables you only need to write methods that take one argume

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.

Once you add your annotated methods and build you should be able to invoke remixer (by doing a 3 finger swipe or clicking a button, depending on how you configured it in the section above), and tweak the variables or trigger the events guarded by the trigger.
Once you add your annotated methods and build you should be able to invoke remixer (by doing a 3 finger swipe or clicking a button, depending on how you configured it in the section above), and tweak the variables.

##### Range variables
__Note:__ for the time being they only support Integers, not floats or doubles.
Expand All @@ -124,7 +134,7 @@ They support the following properties:
- `minValue` the minimum value, if not set assumes 0
- `maxValue` the maximum value, if not set assumes 100
- `increment` the increment between two steps of the range, 1 by default.
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.
- `layoutId` a layoutId to display this, must implement RemixerWidget. It assumes a sensible default if unset.

A Range variable that goes from 15 to 70 and starts at 20 by default:
```java
Expand All @@ -142,7 +152,7 @@ They support the following properties:
- `key` the key for this variable, you can use it to share the same value across activities, if not set it assumes the method name.
- `title` the displayable name of the variable, if not set assumes `key`
- `defaultValue` the initial value, if not set assumes `false`
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.
- `layoutId` a layoutId to display this, must implement RemixerWidget. It assumes a sensible default if unset.

A Boolean variable that has true as a default value:
```java
Expand All @@ -160,7 +170,7 @@ They support the following properties:
- `title` the displayable name of the variable, if not set assumes `key`
- `defaultValue` the initial value, if not set assumes the first in the `possibleValues` list
- `possibleValues` the list of possible values.
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.
- `layoutId` a layoutId to display this, must implement RemixerWidget. It assumes a sensible default if unset.

A String List variable that sets fonts from a list and defaults to the first in the list:
```java
Expand All @@ -176,7 +186,7 @@ public void setTitleFont(String fontName) {
- `key` the key for this variable, you can use it to share the same value across activities, if not set it assumes the method name.
- `title` the displayable name of the variable, if not set assumes `key`
- `defaultValue` the initial value, if not set assumes the empty string.
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.
- `layoutId` a layoutId to display this, must implement RemixerWidget. It assumes a sensible default if unset.

A String variable that sets freeform example text:
```java
Expand All @@ -191,7 +201,7 @@ public void setExampleText(String exampleText) {
- `title` the displayable name of the variable, if not set assumes `key`
- `defaultValue` the initial value, if not set assumes the first in the `possibleValues` list
- `possibleValues` the list of possible values.
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.
- `layoutId` a layoutId to display this, must implement RemixerWidget. It assumes a sensible default if unset.

A variable that lets you pick colors from a list, this example uses a custom layout id to guarantee that it's treated as a Color:
```java
Expand All @@ -203,19 +213,6 @@ public void setTitleColor(Integer color) {
}
```

##### Trigger

- `key` the key for this trigger, you can use it to share the same value across activities, if not set it assumes the method name.
- `title` the displayable name of the trigger, if not set assumes `key`
- `layoutId` a layoutId to display this, must implement RemixerItemWidget. It assumes a sensible default if unset.

A trigger to simulate an event happening:
```java
@TriggerMethod
public void simulateConnectionFailure() {
}
```

## Building

1. Clone the repository
Expand Down
25 changes: 24 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ buildscript {
}

dependencies {
classpath 'com.android.tools.build:gradle:2.2.2'
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
classpath 'com.vanniktech:gradle-android-junit-jacoco-plugin:0.5.0'
Expand All @@ -45,6 +45,29 @@ subprojects {
configFile = rootProject.file('checkstyle.xml')
toolVersion = '7.1'
}

ext {
sourceSetForJavadoc = null
classpathForJavadoc = null
}

afterEvaluate { project ->
if (project.name != ":remixer") {
// Create the sourceset and classpath variables.
if (project.hasProperty('android')) {
project.ext {
sourceSetForJavadoc = project.android.sourceSets.main.java.sourceFiles
classpathForJavadoc = files(project.android.getBootClasspath().join(File.pathSeparator)) + project.configurations.compile
}
} else {
project.ext {
sourceSetForJavadoc = sourceSets.main.allJava
classpathForJavadoc = sourceSets.main.compileClasspath
}
}
}
}

}

task clean(type: Delete) {
Expand Down
4 changes: 2 additions & 2 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#Mon Dec 12 15:47:22 EST 2016
#Fri Jan 06 14:38:33 EST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.2.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.2.1-all.zip
39 changes: 39 additions & 0 deletions remixer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,42 @@ dependencies {
compile project(':remixer_storage')
compile project(':remixer_ui')
}

def javadocProjects = [
":remixer_core",
":remixer_annotation",
":remixer_ui",
":remixer_storage"
]

// Make this project depend on complete evaluation of all the javadoc-generating projects.
// This lets us use the ext variables generated in afterEvaluate.
javadocProjects.each {
evaluationDependsOn(it)
}

// Task that generates javadoc scoped across all subprojects in javadocProjects.
task allJavadoc(type: Javadoc) {
failOnError false
options.showAll()
source javadocProjects.collect { project(it).ext.sourceSetForJavadoc }
classpath = files(javadocProjects.collect { project(it).ext.classpathForJavadoc })
destinationDir = file("${buildDir}/docs/javadoc")
}

task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}

task javadocJar(type: Jar, dependsOn: allJavadoc) {
classifier = 'javadoc'
destinationDir = file("${buildDir}/docs/")
from allJavadoc.destinationDir
}

artifacts {
archives sourcesJar
archives javadocJar
}

Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,20 @@

import com.google.android.libraries.remixer.DataType;
import com.google.android.libraries.remixer.ItemListVariable;
import com.google.android.libraries.remixer.annotation.IntegerListVariableMethod;
import com.google.android.libraries.remixer.annotation.ColorListVariableMethod;
import com.google.android.libraries.remixer.annotation.NumberListVariableMethod;
import com.google.android.libraries.remixer.annotation.StringListVariableMethod;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import java.util.ArrayList;
import java.util.Locale;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;

/**
* Generates code to support {@link StringListVariableMethod} and {@link IntegerListVariableMethod}
* Generates code to support {@link StringListVariableMethod} and {@link ColorListVariableMethod}
* annotations.
*/
class ItemListVariableMethodAnnotation<T> extends MethodAnnotation {
Expand All @@ -40,16 +42,25 @@ class ItemListVariableMethodAnnotation<T> extends MethodAnnotation {
private static final String LIST_SUFFIX = "_variable_list";

/**
* Statement to add a value to the list of possible values.
* Statement format for String.format to add a value to the list of possible values.
*/
private static final String ADD_ITEM = "$L.add($L)";
private static final String ADD_ITEM_FORMAT = "$L.add(%s)";
/**
* Statement to add a string value to the list of possible values.
*
* <p>The difference lies in treating the value as a string (escaping it in quotes) instead
* of a literal (variable name or primitive constant).
* Statement format for String.format to set the default value.
*/
private static final String SET_DEFAULT_FORMAT = "$L.setDefaultValue(%s)";
/**
* Javapoet format escaping for float values
*/
private static final String FLOAT_JAVAPOET_ESCAPING = "$Lf";
/**
* Javapoet format escaping for integer values
*/
private static final String INTEGER_JAVAPOET_ESCAPING = "$L";
/**
* Javapoet format escaping for string values
*/
private static final String ADD_STRING_ITEM = "$L.add($S)";
private static final String STRING_JAVAPOET_ESCAPING = "$S";
/**
* Statement to create an object through a no-parameter constructor.
*
Expand Down Expand Up @@ -80,10 +91,10 @@ static ItemListVariableMethodAnnotation<String> forStringListVariableMethod(
"");
}

static ItemListVariableMethodAnnotation<Integer> forIntegerListVariableMethod(
static ItemListVariableMethodAnnotation<Integer> forColorListVariableMethod(
TypeElement sourceClass,
ExecutableElement sourceMethod,
IntegerListVariableMethod annotation)
ColorListVariableMethod annotation)
throws RemixerAnnotationException {
Integer[] possibleValues = new Integer[annotation.possibleValues().length];
for (int i = 0; i < annotation.possibleValues().length; i++) {
Expand All @@ -92,7 +103,7 @@ static ItemListVariableMethodAnnotation<Integer> forIntegerListVariableMethod(
return new ItemListVariableMethodAnnotation<>(
sourceClass,
sourceMethod,
annotation.isColor() ? DataType.COLOR : DataType.NUMBER,
DataType.COLOR,
ParameterizedTypeName.get(
ClassName.get(ItemListVariable.Builder.class), ClassName.get(Integer.class)),
annotation.key(),
Expand All @@ -103,6 +114,29 @@ static ItemListVariableMethodAnnotation<Integer> forIntegerListVariableMethod(
0);
}

static ItemListVariableMethodAnnotation<Float> forNumberListVariableMethod(
TypeElement sourceClass,
ExecutableElement sourceMethod,
NumberListVariableMethod annotation)
throws RemixerAnnotationException {
Float[] possibleValues = new Float[annotation.possibleValues().length];
for (int i = 0; i < annotation.possibleValues().length; i++) {
possibleValues[i] = annotation.possibleValues()[i];
}
return new ItemListVariableMethodAnnotation<>(
sourceClass,
sourceMethod,
DataType.NUMBER,
ParameterizedTypeName.get(
ClassName.get(ItemListVariable.Builder.class), ClassName.get(Float.class)),
annotation.key(),
annotation.title(),
annotation.layoutId(),
possibleValues,
annotation.defaultValue(),
0f);
}

/**
* Constructs an ItemListVariableMethodAnnotation and makes sure that the constraints for these
* annotations are met.
Expand Down Expand Up @@ -160,19 +194,26 @@ public void addSpecificSetupStatements(MethodSpec.Builder methodBuilder) {
ParameterizedTypeName.get(ClassName.get(ArrayList.class),
ClassName.get(dataType.getValueClass()));
methodBuilder.addStatement(CREATE_NEW_OBJECT, listType, listName, listType);
String addValueStatement = getAddValueStatement();
String addValueStatement =
String.format(Locale.getDefault(), ADD_ITEM_FORMAT, getJavaPoetEscaping());
for (T value : possibleValues) {
methodBuilder.addStatement(addValueStatement, listName, value);
}
methodBuilder.addStatement("$L.setPossibleValues($L)", remixerItemName, listName);

methodBuilder.addStatement(
defaultValue.getClass().equals(String.class)
? "$L.setDefaultValue($S)" : "$L.setDefaultValue($L)",
remixerItemName, defaultValue);
String setDefaultValueStatement =
String.format(Locale.getDefault(), SET_DEFAULT_FORMAT, getJavaPoetEscaping());
methodBuilder.addStatement(setDefaultValueStatement, remixerItemName, defaultValue);
}

private String getAddValueStatement() {
return defaultValue.getClass().equals(String.class) ? ADD_STRING_ITEM : ADD_ITEM;
private String getJavaPoetEscaping() {
if (dataType.getName().equals(DataType.STRING.getName()))
return STRING_JAVAPOET_ESCAPING;
if (dataType.getName().equals(DataType.COLOR.getName()))
return INTEGER_JAVAPOET_ESCAPING;
// If it is an item list it can only be either String, Color or a number, since it's neither
// color nor number at this point, just assume that it's a number so return
// FLOAT_JAVAPOET_ESCAPING.
return FLOAT_JAVAPOET_ESCAPING;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import com.google.android.libraries.remixer.Callback;
import com.google.android.libraries.remixer.DataType;
import com.google.android.libraries.remixer.Remixer;
import com.google.android.libraries.remixer.RemixerItem;
import com.google.android.libraries.remixer.Variable;
import com.google.common.base.Strings;
import com.squareup.javapoet.ClassName;
Expand Down Expand Up @@ -63,7 +62,7 @@ abstract class MethodAnnotation {
*/
static final String INIT_VARIABLE_STATEMENT = "$L.init()";
/**
* Statement to add a remixer item instance to the current remixer.
* Statement to add a variable to the current remixer.
*/
static final String ADD_VARIABLE_STATEMENT = "remixer.addItem($L)";
protected static final String ACTIVITY_NAME = "activity";
Expand Down
Loading

0 comments on commit 62d8db3

Please sign in to comment.