Skip to content

Commit

Permalink
Gif like button added.
Browse files Browse the repository at this point in the history
GifItem - isLiked is a state. This commit shows that even though props are immutable, we can use states. Even though states get updated, we do not change props and litho supports this well.

I have added PreferenceLikeStore which stores whether the gif is liked or not. In GifItemView, we are passing GifCallback as a prop to update prefreences. This prop is optional so we can also pass a null value.

Signed-off-by: Jay Rambhia <[email protected]>
  • Loading branch information
jayrambhia committed Apr 24, 2017
1 parent af78d50 commit 1ce08c2
Show file tree
Hide file tree
Showing 18 changed files with 190 additions and 48 deletions.
38 changes: 27 additions & 11 deletions app/src/main/java/com/fenchtose/lithogifsearch/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import com.facebook.litho.ComponentContext;
import com.facebook.litho.LithoView;
import com.facebook.litho.widget.RecyclerBinder;
import com.fenchtose.lithogifsearch.components.GifItemViewSpec;
import com.fenchtose.lithogifsearch.components.HomeComponent;
import com.fenchtose.lithogifsearch.components.HomeComponentSpec;
import com.fenchtose.lithogifsearch.models.GifItem;
import com.fenchtose.lithogifsearch.models.api.GifProvider;
import com.fenchtose.lithogifsearch.models.db.LikeStore;
import com.fenchtose.lithogifsearch.models.db.PreferenceLikeStore;
import com.fenchtose.lithogifsearch.utils.GifListUtils;

import java.util.List;
Expand All @@ -29,29 +32,42 @@ protected void onCreate(Bundle savedInstanceState) {

final RequestManager glide = Glide.with(this);

final GifProvider gifProvider = new GifProvider(new GifProvider.ResposneListener() {
final LikeStore likeStore = new PreferenceLikeStore(this);

final GifItemViewSpec.GifCallback callback = new GifItemViewSpec.GifCallback() {
@Override
public void onGifLiked(String id, boolean liked) {
likeStore.setLiked(id, liked);
}
};

final GifProvider.ResponseListener responseListener = new GifProvider.ResponseListener() {
@Override
public void onSuccess(List<GifItem> gifs) {
GifListUtils.updateContent(c, binder, glide, gifs);
GifListUtils.updateContent(c, binder, glide, gifs, callback);
}

@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
};

final GifProvider gifProvider = new GifProvider(responseListener, likeStore);

final HomeComponentSpec.OnQueryUpdateListener queryListener = new HomeComponentSpec.OnQueryUpdateListener() {
@Override
public void onQueryUpdated(String query) {
if (query.length() >= 6) {
gifProvider.search(query);
}
}
};

final Component component = HomeComponent.create(c)
.hint("Search Gif")
.binder(binder)
.listener(new HomeComponentSpec.OnQueryUpdateListener() {
@Override
public void onQueryUpdated(String query) {
if (query.length() >= 6) {
gifProvider.search(query);
}
}
})
.listener(queryListener)
.build();

final LithoView view = LithoView.create(this, component);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.fenchtose.lithogifsearch.components;

import android.graphics.Color;
import android.widget.ImageView;

import com.bumptech.glide.RequestManager;
import com.facebook.litho.ComponentContext;
import com.facebook.litho.ComponentLayout;
import com.facebook.litho.Output;
import com.facebook.litho.Size;
import com.facebook.litho.annotations.FromPrepare;
import com.facebook.litho.annotations.MountSpec;
import com.facebook.litho.annotations.OnCreateMountContent;
import com.facebook.litho.annotations.OnMeasure;
import com.facebook.litho.annotations.OnMount;
import com.facebook.litho.annotations.OnPrepare;
import com.facebook.litho.annotations.Prop;
import com.facebook.litho.utils.MeasureUtils;
import com.fenchtose.lithogifsearch.models.GifItem;

@MountSpec
public class GifImageViewSpec {

@OnPrepare
static void onPrepare(ComponentContext context, @Prop GifItem gif, Output<Float> ratio) {
ratio.set((float) gif.getWidth() / gif.getHeight());
}

@OnMeasure
static void onMeasure(ComponentContext c, ComponentLayout layout, int widthSpec, int heightSpec, Size size, @FromPrepare float ratio) {
// Not using ratio as of now
MeasureUtils.measureWithAspectRatio(widthSpec, heightSpec, 1, size);
}

@OnCreateMountContent
static ImageView onCreateMountContent(ComponentContext c) {
ImageView view = new ImageView(c.getApplicationContext());
view.setAdjustViewBounds(true);
view.setBackgroundColor(Color.WHITE);
view.setScaleType(ImageView.ScaleType.CENTER);
return view;
}

@OnMount
static void onMount(ComponentContext c, ImageView view, @Prop RequestManager glide, @Prop GifItem gif) {
glide.load(gif.getImage()).asGif().into(view);
}
}
Original file line number Diff line number Diff line change
@@ -1,49 +1,71 @@
package com.fenchtose.lithogifsearch.components;

import android.graphics.Color;
import android.widget.ImageView;

import com.bumptech.glide.RequestManager;
import com.facebook.litho.ClickEvent;
import com.facebook.litho.Column;
import com.facebook.litho.ComponentContext;
import com.facebook.litho.ComponentLayout;
import com.facebook.litho.Output;
import com.facebook.litho.Size;
import com.facebook.litho.annotations.FromPrepare;
import com.facebook.litho.annotations.MountSpec;
import com.facebook.litho.annotations.OnCreateMountContent;
import com.facebook.litho.annotations.OnMeasure;
import com.facebook.litho.annotations.OnMount;
import com.facebook.litho.annotations.OnPrepare;
import com.facebook.litho.StateValue;
import com.facebook.litho.annotations.LayoutSpec;
import com.facebook.litho.annotations.OnCreateInitialState;
import com.facebook.litho.annotations.OnCreateLayout;
import com.facebook.litho.annotations.OnEvent;
import com.facebook.litho.annotations.OnUpdateState;
import com.facebook.litho.annotations.Prop;
import com.facebook.litho.utils.MeasureUtils;
import com.facebook.litho.annotations.State;
import com.facebook.litho.widget.Image;
import com.facebook.yoga.YogaAlign;
import com.facebook.yoga.YogaEdge;
import com.facebook.yoga.YogaPositionType;
import com.fenchtose.lithogifsearch.R;
import com.fenchtose.lithogifsearch.models.GifItem;

@MountSpec
@LayoutSpec
public class GifItemViewSpec {

public static final String TAG = GifItemViewSpec.class.getSimpleName();
@OnCreateInitialState
static void createInitialState(ComponentContext c, StateValue<Boolean> isLiked, @Prop boolean initLiked) {
isLiked.set(initLiked);
}

@OnPrepare
static void onPrepare(ComponentContext context, @Prop GifItem gif, Output<Float> ratio) {
ratio.set((float) gif.getWidth() / gif.getHeight());
@OnCreateLayout
static ComponentLayout onCreateLayout(ComponentContext context, @Prop GifItem gif,
@Prop RequestManager glide, @State boolean isLiked) {
return Column.create(context)
.child(GifImageView.create(context)
.gif(gif)
.glide(glide)
.withLayout()
.alignSelf(YogaAlign.CENTER)
.build())
.child(Image.create(context)
.drawableRes(isLiked ? R.drawable.ic_favorite_accent_24dp :R.drawable.ic_favorite_border_accent_24dp)
.withLayout()
.clickHandler(GifItemView.onLikeButtonClicked(context))
.positionType(YogaPositionType.ABSOLUTE)
.widthDip(40)
.heightDip(40)
.paddingDip(YogaEdge.ALL, 8)
.alignSelf(YogaAlign.FLEX_END)
.build()
).build();
}

@OnMeasure
static void onMeasure(ComponentContext c, ComponentLayout layout, int widthSpec, int heightSpec, Size size, @FromPrepare float ratio) {
MeasureUtils.measureWithAspectRatio(widthSpec, heightSpec, ratio, size);
@OnUpdateState
static void updateLikeButton(StateValue<Boolean> isLiked) {
isLiked.set(!isLiked.get());
}

@OnCreateMountContent
static ImageView onCreateMountContent(ComponentContext c) {
ImageView view = new ImageView(c.getApplicationContext());
view.setAdjustViewBounds(true);
view.setBackgroundColor(Color.WHITE);
view.setScaleType(ImageView.ScaleType.CENTER);
return view;
@OnEvent(ClickEvent.class)
static void onLikeButtonClicked(ComponentContext c, @State boolean isLiked, @Prop GifItem gif, @Prop (optional = true) GifCallback callback) {
if (callback != null) {
callback.onGifLiked(gif.getId(), !isLiked);
}

GifItemView.updateLikeButtonAsync(c);
}

@OnMount
static void onMount(ComponentContext c, ImageView view, @Prop RequestManager glide, @Prop GifItem gif) {
glide.load(gif.getImage()).asGif().into(view);
public interface GifCallback {
void onGifLiked(String id, boolean liked);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ public class GifItem {
private final String image;
private final int width;
private final int height;
private final boolean isLiked;

public GifItem(JsonObject json) {
public GifItem(JsonObject json, boolean isLiked) {
this.id = json.get("id").getAsString();
JsonObject image = json.get("images").getAsJsonObject().get("original").getAsJsonObject();
this.image = image.get("url").getAsString();
this.width = image.get("width").getAsInt();
this.height = image.get("height").getAsInt();
this.isLiked = isLiked;
}

public String getId() {
Expand All @@ -32,4 +34,9 @@ public int getWidth() {
public int getHeight() {
return height;
}

public boolean isLiked() {
return isLiked;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.support.annotation.NonNull;

import com.fenchtose.lithogifsearch.models.GifItem;
import com.fenchtose.lithogifsearch.models.db.LikeStore;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

Expand All @@ -18,16 +19,18 @@
public class GifProvider {

private GifApi api;
private final ResposneListener listener;
private final ResponseListener listener;
private final LikeStore likeStore;

public GifProvider(ResposneListener listener) {
public GifProvider(ResponseListener listener, LikeStore store) {
this.listener = listener;
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(GifApi.ENDPOINT)
.addConverterFactory(GsonConverterFactory.create())
.build();

api = retrofit.create(GifApi.class);
this.likeStore = store;
}

public void search(@NonNull String query) {
Expand All @@ -39,7 +42,7 @@ public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
List<GifItem> gifs = new ArrayList<>();
for (int i=0; i<data.size(); i++) {
JsonObject json = data.get(i).getAsJsonObject();
gifs.add(new GifItem(json));
gifs.add(new GifItem(json, likeStore.isLiked(json.get("id").getAsString())));
}

listener.onSuccess(gifs);
Expand All @@ -52,7 +55,7 @@ public void onFailure(Call<JsonObject> call, Throwable t) {
});
}

public interface ResposneListener {
public interface ResponseListener {
void onSuccess(List<GifItem> gifs);
void onFailure(Throwable t);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.fenchtose.lithogifsearch.models.db;


public interface LikeStore {
void setLiked(String id, boolean liked);
boolean isLiked(String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.fenchtose.lithogifsearch.models.db;

import android.content.Context;
import android.content.SharedPreferences;

public class PreferenceLikeStore implements LikeStore {

private final SharedPreferences preferences;

private static final String PREFERENCE_NAME = "like_store";

public PreferenceLikeStore(Context context) {
preferences = context.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE);
}

@Override
public void setLiked(String id, boolean liked) {
SharedPreferences.Editor editor = preferences.edit();

if (liked) {
editor.putBoolean(id, true);
} else {
editor.remove(id);
}

editor.apply();
}

@Override
public boolean isLiked(String id) {
return preferences.getBoolean(id, false);
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,23 @@
package com.fenchtose.lithogifsearch.utils;

import android.content.Context;
import android.support.annotation.Nullable;

import com.bumptech.glide.RequestManager;
import com.facebook.litho.ComponentContext;
import com.facebook.litho.ComponentInfo;
import com.facebook.litho.widget.GridLayoutInfo;
import com.facebook.litho.widget.RecyclerBinder;
import com.fenchtose.lithogifsearch.components.GifItemView;
import com.fenchtose.lithogifsearch.components.GifItemViewSpec;
import com.fenchtose.lithogifsearch.models.GifItem;

import java.util.ArrayList;
import java.util.List;

public class GifListUtils {
public static void updateContent(ComponentContext c, RecyclerBinder binder, RequestManager glide, List<GifItem> gifs) {
public static void updateContent(ComponentContext c, RecyclerBinder binder, RequestManager glide,
List<GifItem> gifs, @Nullable GifItemViewSpec.GifCallback callback) {

binder.removeRangeAt(0, binder.getItemCount());

Expand All @@ -25,6 +28,8 @@ public static void updateContent(ComponentContext c, RecyclerBinder binder, Requ
GifItemView.create(c)
.gif(gif)
.glide(glide)
.initLiked(gif.isLiked())
.callback(callback)
.key(gif.getId())
.build()
).build()
Expand All @@ -36,6 +41,6 @@ public static void updateContent(ComponentContext c, RecyclerBinder binder, Requ
}

public static RecyclerBinder getBinder(ComponentContext c, Context context) {
return new RecyclerBinder(c, new GridLayoutInfo(context, 3));
return new RecyclerBinder(c, new GridLayoutInfo(context, 2));
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1ce08c2

Please sign in to comment.