Skip to content

Instantly share code, notes, and snippets.

@winzillion
Last active November 13, 2017 03:25
Show Gist options
  • Save winzillion/49a2311422259f3f06d371b8f458f4e6 to your computer and use it in GitHub Desktop.
Save winzillion/49a2311422259f3f06d371b8f458f4e6 to your computer and use it in GitHub Desktop.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/item_todo" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context=".MainActivity">
<Spinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="LinearLayoutManager"
tools:listitem="@layout/item_todo" />
</LinearLayout>
public class AddDialogFragment extends AppCompatDialogFragment {
@Nullable
@Override
public View onCreateView(final LayoutInflater inInflater,
@Nullable final ViewGroup inContainer,
@Nullable final Bundle inSavedInstanceState) {
return inInflater.inflate(R.layout.dialog_add, inContainer);
}
@NonNull
@Override
public Dialog onCreateDialog(final Bundle inSavedInstanceState) {
final AlertDialog.Builder builder = new AlertDialog.Builder(super.getActivity());
final LayoutInflater inflater = super.getActivity().getLayoutInflater();
final ViewGroup nullParent = null;
// display an alertDialog for input a new todo item
builder.setView(inflater.inflate(R.layout.dialog_add, nullParent))
.setTitle(R.string.dialog_title)
.setPositiveButton(R.string.add, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface inDialog, final int inId) {
final AlertDialog alertDialog = (AlertDialog)inDialog;
final Todo todo = new Todo();
final EditText title = (EditText)alertDialog.findViewById(R.id.title);
final EditText memo = (EditText)alertDialog.findViewById(R.id.memo);
final EditText dueDate = (EditText)alertDialog.findViewById(R.id.dueText);
if (title != null) {
todo.title = title.getText().toString();
}
if (memo != null) {
todo.memo = memo.getText().toString();
}
if (dueDate != null) {
todo.dueDate = dueDate.getText().toString();
}
// the input data will be sent to store by using bus
FluxContext.getInstance()
.getActionCreator()
.sendRequestAsync(TODO_ADD, todo);
}
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(final DialogInterface inDialog, final int inId) {
// Do nothing
}
});
return builder.create();
}
}
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'org.codehaus.groovy:groovy-android-gradle-plugin:1.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
apply plugin: 'com.android.application'
apply plugin: 'groovyx.android'
android {
compileSdkVersion 24
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.example.sampleapp”
minSdkVersion 9
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
testOptions {
unitTests.returnDefaultValues = true
}
packagingOptions {
exclude 'META-INF/services/org.codehaus.groovy.transform.ASTTransformation'
exclude 'META-INF/services/org.codehaus.groovy.runtime.ExtensionModule'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'org.codehaus.groovy:groovy-all:2.4.7'
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'org.robospock:robospock:1.0.1'
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile('com.android.support.test.espresso:espresso-contrib:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestCompile 'org.codehaus.groovy:groovy:2.4.7:grooid'
androidTestCompile('org.spockframework:spock-core:1.0-groovy-2.4') {
exclude group: 'org.codehaus.groovy'
exclude group: 'junit'
}
}
public class Bus implements IFluxBus {
private EventBus mBus = EventBus.getDefault();
@Override
public void register(final Object inSubscriber) {
this.mBus.register(inSubscriber);
}
@Override
public void unregister(final Object inSubscriber) {
this.mBus.unregister(inSubscriber);
}
@Override
public void post(final Object inEvent) {
this.mBus.post(inEvent);
}
}
class BusSpec extends Specification {
public static class Subscriber {
Object actualEvent;
@Subscribe
public onEvent(String inEvent) {
this.actualEvent = inEvent;
}
}
def "Test register"() {
given:
def target = new Bus()
def expected = "Test"
def subscriber = new Subscriber()
def constants = new Constants()
target.register(subscriber)
when: "post an event with unexpected type"
target.post(0)
then: "will not get the event"
subscriber.actualEvent == null
constants != null
when: "post an event with expected type"
target.post(expected)
then: "get the event"
subscriber.actualEvent == expected
}
def "Test unregister"() {
given:
def target = new Bus()
def expected = "Test"
def subscriber = new Subscriber()
target.register(subscriber)
when: "post an event"
target.post(expected)
then: "get the event"
subscriber.actualEvent == expected
when: "unregister"
subscriber.actualEvent = null
target.unregister(subscriber)
target.post(expected)
then: "will not get any event"
subscriber.actualEvent == null
}
}
// constants for data type
public static final int DATA_USER = 10;
public static final int DATA_TODO = 20;
// constants for actions of user data
public static final int USER_LOAD = DATA_USER + 1;
// constants for actions of todo data
public static final int TODO_LOAD = DATA_TODO + 1;
public static final int TODO_ADD = DATA_TODO + 2;
public static final int TODO_CLOSE = DATA_TODO + 3;
public class CustomJUnitRunner extends AndroidJUnitRunner {
@Override
public Application newApplication(final ClassLoader inClassLoader,
final String inClassName,
final Context inContext)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return super.newApplication(inClassLoader, StubAppConfig.class.getName(), inContext);
}
}
defaultConfig {
...
// replace "android.support.test.runner.AndroidJUnitRunner" with custom one
testInstrumentationRunner "com.example.fluxjava.rx.CustomJUnitRunner"
}
defaultConfig {
...
// replace "android.support.test.runner.AndroidJUnitRunner" with custom one
testInstrumentationRunner "com.example.fluxjava.rx2.CustomJUnitRunner"
}
defaultConfig {
...
// replace "android.support.test.runner.AndroidJUnitRunner" with custom one
testInstrumentationRunner "com.example.fluxjava.eventbus.CustomJUnitRunner"
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title" />
<EditText
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:inputType="text" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/memo" />
<EditText
android:id="@+id/memo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:inputType="text" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/due_date" />
<EditText
android:id="@+id/dueText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:inputType="text" />
</LinearLayout>
</LinearLayout>
public Class<?> getActionClass(final Object inActionTypeId) {
Class<?> result = null;
if (inActionTypeId instanceof Integer) {
final int typeId = (int)inActionTypeId;
// return action type by pre-define id
switch (typeId) {
case USER_LOAD:
result = UserAction.class;
break;
case TODO_LOAD:
case TODO_ADD:
case TODO_CLOSE:
result = TodoAction.class;
break;
}
}
return result;
}
@Override
public User getItem(final int inIndex) {
return new User(this.mList.get(inIndex));
}
public class MainActivity extends AppCompatActivity {
private UserAdapter mUserAdapter;
private TodoAdapter mTodoAdapter;
@Override
protected void onCreate(final Bundle inSavedInstanceState) {
super.onCreate(inSavedInstanceState);
super.setContentView(R.layout.activity_main);
this.setupRecyclerView();
this.setupSpinner();
}
@Override
protected void onStart() {
super.onStart();
// ask to get the list of user
FluxContext.getInstance().getActionCreator().sendRequestAsync(USER_LOAD, USER_LOAD);
}
@Override
protected void onStop() {
super.onStop();
// release resources
if (this.mUserAdapter != null) {
this.mUserAdapter.dispose();
}
if (this.mTodoAdapter != null) {
this.mTodoAdapter.dispose();
}
}
private void setupSpinner() {
final Spinner spinner = (Spinner)super.findViewById(R.id.spinner);
if (spinner != null) {
// configure spinner to show data
this.mUserAdapter = new UserAdapter();
spinner.setAdapter(this.mUserAdapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(final AdapterView<?> inParent, final View inView,
final int inPosition, final long inId) {
// when user change the selection of spinner, change the list of recyclerView
FluxContext.getInstance()
.getActionCreator()
.sendRequestAsync(TODO_LOAD, TODO_LOAD + ":" + inPosition);
}
@Override
public void onNothingSelected(final AdapterView<?> inParent) {
// Do nothing
}
});
}
}
private void setupRecyclerView() {
final RecyclerView recyclerView = (RecyclerView)super.findViewById(R.id.recyclerView);
if (recyclerView != null) {
// configure recyclerView to show data
this.mTodoAdapter = new TodoAdapter();
recyclerView.setAdapter(this.mTodoAdapter);
}
}
}
@Config(constants = BuildConfig, sdk = 21, application = StubAppConfig)
class MainActivitySpec extends GradleRoboSpecification {
}
@Title("Manage todo items")
@Narrative("""
As a user
I want to manage todo items
So I can track something to be done
""")
class ManageTodoStory extends Specification {
def "Add a todo"() {
when: "I tap the add menu on main activity"
then: "I see the add todo screen"
when: "I input todo detail and press ADD button"
then: "I see a new entry in list"
}
def "Add a todo, but cancel the action"() {
when: "I tap the add menu on main activity"
and: "I press cancel button"
then: "Nothing happen"
}
def "Switch user"() {
when: "I select a different user"
then: "I see the list changed"
}
def "Mark a todo as done"() {
when: "I mark a todo as done"
then: "I see the todo has a check mark and strike through on title"
}
}
@Title("Manage todo items")
@Narrative("""
As a user
I want to manage todo items
So I can track something to be done
""")
class ManageTodoStory extends Specification {
@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class)
private RecyclerView mRecyclerView
def "Add a todo"() {
when: "I tap the add menu on main activity"
this.mRecyclerView = (RecyclerView)this.mActivityRule.activity.findViewById(R.id.recyclerView)
onView(withId(R.id.add)).perform(click())
then: "I see the add todo screen"
onView(withText(R.string.dialog_title))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withText(R.string.title))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withId(R.id.title))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withText(R.string.memo))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withId(R.id.memo))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withText(R.string.due_date))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withId(R.id.dueText))
.inRoot(isDialog())
.check(matches(isDisplayed()))
onView(withId(android.R.id.button1))
.inRoot(isDialog())
.check(matches(withText(R.string.add)))
.check(matches(isDisplayed()))
onView(withId(android.R.id.button2))
.inRoot(isDialog())
.check(matches(withText(android.R.string.cancel)))
.check(matches(isDisplayed()))
when: "I input todo detail and press ADD button"
onView(withId(R.id.title))
.perform(typeText("Test title"))
onView(withId(R.id.memo))
.perform(typeText("Sample memo"))
onView(withId(R.id.dueText))
.perform(typeText("2016/1/1"), closeSoftKeyboard())
onView(withId(android.R.id.button1)).perform(click())
then: "I see a new entry in list"
onView(withText(R.string.dialog_title))
.check(doesNotExist())
this.mRecyclerView.getAdapter().itemCount == 5
onView(withId(R.id.recyclerView)).perform(scrollToPosition(4))
onView(withId(R.id.recyclerView))
.check(matches(hasDescendant(withText("Test title"))))
}
def "Add a todo, but cancel the action"() {
when: "I tap the add menu on main activity"
this.mRecyclerView = (RecyclerView)this.mActivityRule.activity.findViewById(R.id.recyclerView)
onView(withId(R.id.add)).perform(click())
and: "I press cancel button"
onView(withId(android.R.id.button2)).perform(click())
then: "Nothing happen"
this.mRecyclerView.getAdapter().itemCount == 4
}
def "Switch user"() {
when: "I select a different user"
this.mRecyclerView = (RecyclerView)this.mActivityRule.activity.findViewById(R.id.recyclerView)
onView(withId(R.id.spinner)).perform(click())
onView(allOf(withText("User2"), isDisplayed()))
.perform(click())
then: "I see the list changed"
this.mRecyclerView.getAdapter().itemCount == 5
}
def "Mark a todo as done"() {
when: "I mark a todo as done"
TextView target
this.mRecyclerView = (RecyclerView)this.mActivityRule.activity.findViewById(R.id.recyclerView)
onView(withRecyclerView(R.id.recyclerView).atPositionOnView(2, R.id.closed))
.perform(click())
target = (TextView)this.mRecyclerView
.findViewHolderForAdapterPosition(2)
.itemView
.findViewById(R.id.title)
then: "I see the todo has a check mark and strike through on title"
target.getText().toString().equals("Test title 2")
(target.getPaintFlags() & Paint.STRIKE_THRU_TEXT_FLAG) > 0
}
static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) {
return new RecyclerViewMatcher(recyclerViewId)
}
}
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/add"
android:title="@string/add"
app:showAsAction="always" />
</menu>
@Override
protected <TAction extends IFluxAction> void onAction(TAction inAction) {
final UserAction action = (UserAction)inAction;
// base on input action to process data
// in this sample only define one action
switch (action.getType()) {
case USER_LOAD:
this.mList.clear();
this.mList.addAll(action.getData());
super.emitChange(new ListChangeEvent());
break;
}
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onAction(final UserAction inAction) {
// base on input action to process data
// in this sample only define one action
switch (inAction.getType()) {
case USER_LOAD:
this.mList.clear();
this.mList.addAll(inAction.getData());
super.emitChange(new ListChangeEvent());
break;
}
}
@Override
public void onBindViewHolder(final ViewHolder inViewHolder, final int inPosition) {
final Todo item = this.mStore.getItem(inPosition);
// bind data into item view of RecyclerView
inViewHolder.title.setText(item.title);
if (item.closed) {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
}
inViewHolder.dueDate.setText(item.dueDate);
inViewHolder.memo.setText(item.memo);
inViewHolder.closed.setOnCheckedChangeListener(null);
inViewHolder.closed.setChecked(item.closed);
inViewHolder.closed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton inButtonView, final boolean inIsChecked) {
item.closed = inIsChecked;
FluxContext.getInstance()
.getActionCreator()
.sendRequestAsync(TODO_CLOSE, item);
}
});
}
@Override
public boolean onCreateOptionsMenu(final Menu inMenu) {
super.getMenuInflater().inflate(R.menu.menu_main, inMenu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean result;
switch (item.getItemId()) {
case R.id.add:
AddDialogFragment addDialog = new AddDialogFragment();
// display an input dialog to get a new todo
addDialog.show(super.getSupportFragmentManager(), "Add");
result = true;
break;
default:
result = super.onOptionsItemSelected(item);
break;
}
return result;
}
private void setupFlux() {
HashMap<Object, Class<?>> storeMap = new HashMap<>();
storeMap.put(DATA_USER, UserStore.class);
storeMap.put(DATA_TODO, TodoStore.class);
// setup relationship of components in framework
FluxContext.getBuilder()
.setBus(new Bus())
.setActionHelper(new ActionHelper())
.setStoreMap(storeMap)
.build();
}
public class StubAppConfig extends Application {
@Override
public void onCreate() {
super.onCreate();
this.setupFlux();
}
private void setupFlux() {
HashMap<Object, Class<?>> storeMap = new HashMap<>();
storeMap.put(DATA_USER, StubUserStore.class);
storeMap.put(DATA_TODO, StubTodoStore.class);
FluxContext.getBuilder()
.setBus(new Bus())
.setActionHelper(new StubActionHelper())
.setStoreMap(storeMap)
.build();
}
}
public class TodoAdapter extends RecyclerView.Adapter<TodoAdapter.ViewHolder> {
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView dueDate;
TextView memo;
CheckBox closed;
ViewHolder(final View inItemView) {
super(inItemView);
this.title = (TextView)inItemView.findViewById(R.id.title);
this.dueDate = (TextView)inItemView.findViewById(R.id.dueDate);
this.memo = (TextView)inItemView.findViewById(R.id.memo);
this.closed = (CheckBox)inItemView.findViewById(R.id.closed);
}
}
private TodoStore mStore;
public TodoAdapter() {
// get the instance of store that will provide data
this.mStore = (TodoStore)FluxContext.getInstance().getStore(DATA_TODO, null, null);
this.mStore.toObservable(TodoStore.ListChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<TodoStore.ListChangeEvent>() {
@Override
public void call(final TodoStore.ListChangeEvent inEvent) {
TodoAdapter.super.notifyDataSetChanged();
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable inThrowable) {
// put error handle here
}
});
this.mStore.toObservable(TodoStore.ItemChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<TodoStore.ItemChangeEvent>() {
@Override
public void call(final TodoStore.ItemChangeEvent inEvent) {
TodoAdapter.super.notifyItemChanged(inEvent.position);
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable inThrowable) {
// put error handle here
}
});
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup inParent, final int inViewType) {
final View itemView = LayoutInflater
.from(inParent.getContext()).inflate(R.layout.item_todo, inParent, false);
// use custom ViewHolder to display data
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder inViewHolder, final int inPosition) {
final Todo item = this.mStore.getItem(inPosition);
// bind data into item view of RecyclerView
inViewHolder.title.setText(item.title);
if (item.closed) {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
}
inViewHolder.dueDate.setText(item.dueDate);
inViewHolder.memo.setText(item.memo);
inViewHolder.closed.setOnCheckedChangeListener(null);
inViewHolder.closed.setChecked(item.closed);
inViewHolder.closed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton inButtonView, final boolean inIsChecked) {
item.closed = inIsChecked;
FluxContext.getInstance()
.getActionCreator()
.sendRequestAsync(TODO_CLOSE, item);
}
});
}
@Override
public int getItemCount() {
return this.mStore.getCount();
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
public class TodoAdapter extends RecyclerView.Adapter<TodoAdapter.ViewHolder> {
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView dueDate;
TextView memo;
CheckBox closed;
ViewHolder(final View inItemView) {
super(inItemView);
this.title = (TextView)inItemView.findViewById(R.id.title);
this.dueDate = (TextView)inItemView.findViewById(R.id.dueDate);
this.memo = (TextView)inItemView.findViewById(R.id.memo);
this.closed = (CheckBox)inItemView.findViewById(R.id.closed);
}
}
private TodoStore mStore;
public TodoAdapter() {
// get the instance of store that will provide data
this.mStore = (TodoStore)FluxContext.getInstance().getStore(DATA_TODO, null, null);
this.mStore.toObservable(TodoStore.ListChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<TodoStore.ListChangeEvent>() {
@Override
public void accept(final TodoStore.ListChangeEvent inEvent) throws Exception {
TodoAdapter.super.notifyDataSetChanged();
}
},
new Consumer<Throwable>() {
@Override
public void accept(final Throwable inThrowable) throws Exception {
// put error handle here
}
});
this.mStore.toObservable(TodoStore.ItemChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<TodoStore.ItemChangeEvent>() {
@Override
public void accept(final TodoStore.ItemChangeEvent inEvent) throws Exception {
TodoAdapter.super.notifyItemChanged(inEvent.position);
}
},
new Consumer<Throwable>() {
@Override
public void accept(final Throwable inThrowable) throws Exception {
// put error handle here
}
});
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup inParent, final int inViewType) {
final View itemView = LayoutInflater
.from(inParent.getContext()).inflate(R.layout.item_todo, inParent, false);
// use custom ViewHolder to display data
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder inViewHolder, final int inPosition) {
final Todo item = this.mStore.getItem(inPosition);
// bind data into item view of RecyclerView
inViewHolder.title.setText(item.title);
if (item.closed) {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
inViewHolder.title.setPaintFlags(
inViewHolder.title.getPaintFlags() & (~ Paint.STRIKE_THRU_TEXT_FLAG));
}
inViewHolder.dueDate.setText(item.dueDate);
inViewHolder.memo.setText(item.memo);
inViewHolder.closed.setOnCheckedChangeListener(null);
inViewHolder.closed.setChecked(item.closed);
inViewHolder.closed.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(final CompoundButton inButtonView, final boolean inIsChecked) {
item.closed = inIsChecked;
FluxContext.getInstance()
.getActionCreator()
.sendRequestAsync(TODO_CLOSE, item);
}
});
}
@Override
public int getItemCount() {
return this.mStore.getCount();
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
public class TodoAdapter extends RecyclerView.Adapter<TodoAdapter.ViewHolder> {
static class ViewHolder extends RecyclerView.ViewHolder {
TextView title;
TextView dueDate;
TextView memo;
CheckBox closed;
ViewHolder(final View inItemView) {
super(inItemView);
this.title = (TextView)inItemView.findViewById(R.id.title);
this.dueDate = (TextView)inItemView.findViewById(R.id.dueDate);
this.memo = (TextView)inItemView.findViewById(R.id.memo);
this.closed = (CheckBox)inItemView.findViewById(R.id.closed);
}
}
private TodoStore mStore;
public TodoAdapter() {
// get the instance of store that will provide data
this.mStore = (TodoStore)FluxContext.getInstance().getStore(DATA_TODO, null, this);
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup inParent, final int inViewType) {
final View itemView = LayoutInflater
.from(inParent.getContext()).inflate(R.layout.item_todo, inParent, false);
// use custom ViewHolder to display data
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(final ViewHolder inViewHolder, final int inPosition) {
final Todo item = this.mStore.getItem(inPosition);
// bind data into item view of RecyclerView
inViewHolder.title.setText(item.title);
inViewHolder.dueDate.setText(item.dueDate);
inViewHolder.memo.setText(item.memo);
inViewHolder.closed.setOnCheckedChangeListener(null);
inViewHolder.closed.setChecked(item.closed);
}
@Override
public int getItemCount() {
return this.mStore.getCount();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(final TodoStore.ListChangeEvent inEvent) {
super.notifyDataSetChanged();
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(final TodoStore.ItemChangeEvent inEvent) {
super.notifyItemChanged(inEvent.position);
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
@Override
protected <TAction extends IFluxAction> void onAction(final TAction inAction) {
final TodoAction action = (TodoAction)inAction;
// base on input action to process data
switch (action.getType()) {
case TODO_LOAD:
this.mList.clear();
this.mList.addAll(action.getData());
super.emitChange(new ListChangeEvent());
break;
case TODO_ADD:
this.mList.addAll(action.getData());
super.emitChange(new ListChangeEvent());
break;
case TODO_CLOSE:
for (int j = 0; j < action.getData().size(); j++) {
for (int i = 0; i < this.mList.size(); i++) {
if (this.mList.get(i).id == action.getData().get(j).id) {
this.mList.set(i, action.getData().get(j));
super.emitChange(new ItemChangeEvent(i));
break;
}
}
}
break;
}
}
@Subscribe(threadMode = ThreadMode.BACKGROUND)
public void onAction(final TodoAction inAction) {
// base on input action to process data
switch (inAction.getType()) {
case TODO_LOAD:
this.mList.clear();
this.mList.addAll(inAction.getData());
super.emitChange(new ListChangeEvent());
break;
case TODO_ADD:
this.mList.addAll(inAction.getData());
super.emitChange(new ListChangeEvent());
break;
case TODO_CLOSE:
for (int j = 0; j < inAction.getData().size(); j++) {
for (int i = 0; i < this.mList.size(); i++) {
if (this.mList.get(i).id == inAction.getData().get(j).id) {
this.mList.set(i, inAction.getData().get(j));
super.emitChange(new ItemChangeEvent(i));
break;
}
}
}
break;
}
}
public class UserAdapter extends BaseAdapter {
private UserStore mStore;
public UserAdapter() {
// get the instance of store that will provide data
this.mStore = (UserStore)FluxContext.getInstance().getStore(DATA_USER, null, null);
this.mStore.toObservable(UserStore.ListChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<UserStore.ListChangeEvent>() {
@Override
public void call(UserStore.ListChangeEvent inEvent) {
UserAdapter.super.notifyDataSetChanged();
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable inThrowable) {
// put error handle here
}
});
}
@Override
public int getCount() {
return this.mStore.getCount();
}
@Override
public Object getItem(final int inPosition) {
return this.mStore.getItem(inPosition);
}
@Override
public long getItemId(final int inPosition) {
return inPosition;
}
@Override
public View getView(final int inPosition, final View inConvertView, final ViewGroup inParent) {
View itemView = inConvertView;
// bind data into item view of Spinner
if (itemView == null) {
itemView = LayoutInflater
.from(inParent.getContext())
.inflate(R.layout.item_user, inParent, false);
}
if (itemView instanceof TextView) {
((TextView)itemView).setText(this.mStore.getItem(inPosition).name);
}
return itemView;
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
public UserAdapter() {
// get the instance of store that will provide data
this.mStore = (UserStore)FluxContext.getInstance().getStore(DATA_USER, null, null);
this.mStore.toObservable(UserStore.ListChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Action1<UserStore.ListChangeEvent>() {
@Override
public void call(UserStore.ListChangeEvent inEvent) {
UserAdapter.super.notifyDataSetChanged();
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable inThrowable) {
// put error handle here
}
});
}
public class UserAdapter extends BaseAdapter {
private UserStore mStore;
public UserAdapter() {
// get the instance of store that will provide data
this.mStore = (UserStore)FluxContext.getInstance().getStore(DATA_USER, null, null);
this.mStore.toObservable(UserStore.ListChangeEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
new Consumer<UserStore.ListChangeEvent>() {
@Override
public void accept(final UserStore.ListChangeEvent inEvent) throws Exception {
UserAdapter.super.notifyDataSetChanged();
}
},
new Consumer<Throwable>() {
@Override
public void accept(final Throwable inThrowable) throws Exception {
// put error handle here
}
});
}
@Override
public int getCount() {
return this.mStore.getCount();
}
@Override
public Object getItem(final int inPosition) {
return this.mStore.getItem(inPosition);
}
@Override
public long getItemId(final int inPosition) {
return inPosition;
}
@Override
public View getView(final int inPosition, final View inConvertView, final ViewGroup inParent) {
View itemView = inConvertView;
// bind data into item view of Spinner
if (itemView == null) {
itemView = LayoutInflater
.from(inParent.getContext())
.inflate(R.layout.item_user, inParent, false);
}
if (itemView instanceof TextView) {
((TextView)itemView).setText(this.mStore.getItem(inPosition).name);
}
return itemView;
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
public class UserAdapter extends BaseAdapter {
private UserStore mStore;
public UserAdapter() {
// get the instance of store that will provide data
this.mStore = (UserStore)FluxContext.getInstance().getStore(DATA_USER, null, this);
}
@Override
public int getCount() {
return this.mStore.getCount();
}
@Override
public Object getItem(final int inPosition) {
return this.mStore.getItem(inPosition);
}
@Override
public long getItemId(final int inPosition) {
return inPosition;
}
@Override
public View getView(final int inPosition, final View inConvertView, final ViewGroup inParent) {
View itemView = inConvertView;
// bind data into item view of Spinner
if (itemView == null) {
itemView = LayoutInflater
.from(inParent.getContext())
.inflate(R.layout.item_user, inParent, false);
}
if (itemView instanceof TextView) {
((TextView)itemView).setText(this.mStore.getItem(inPosition).name);
}
return itemView;
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(final UserStore.ListChangeEvent inEvent) {
super.notifyDataSetChanged();
}
public void dispose() {
// Clear object reference to avoid memory leak issue
FluxContext.getInstance().unregisterStore(this.mStore, this);
}
}
public Object wrapData(final Object inData) {
Object result = inData;
// base on data type to convert data into require form
if (inData instanceof Integer) {
result = this.getRemoteData((int)inData, -1);
}
if (inData instanceof String) {
final String[] command = ((String)inData).split(":");
final int action;
final int position;
action = Integer.valueOf(command[0]);
position = Integer.valueOf(command[1]);
result = this.getRemoteData(action, position);
}
if (inData instanceof Todo) {
final ArrayList<Todo> todoList = new ArrayList<>();
this.updateRemoteTodo();
todoList.add((Todo)inData);
result = todoList;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment