diff --git a/app/build.gradle b/app/build.gradle index 445372a..a885b8d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,8 @@ android { applicationId 'ru.yandex.yamblz' minSdkVersion versions.minSdk targetSdkVersion versions.targetSdk - versionCode versions.code // Notice that you may want to use BUILD_NUMBER from CI in real project with own CI. + versionCode versions.code + // Notice that you may want to use BUILD_NUMBER from CI in real project with own CI. versionName versions.name // Make generated apks contain version name and code. @@ -104,6 +105,10 @@ dependencies { compile libraries.tinyDancer compile libraries.lynx compile libraries.processPhoenix + compile libraries.rxjava + compile libraries.rxandroid + compile libraries.okhttp + compile libraries.gson testCompile libraries.junit testCompile libraries.robolectric @@ -121,6 +126,8 @@ dependencies { exclude module: 'recyclerview-v7' exclude module: 'support-v4' } + + } configurations.all { diff --git a/app/src/main/java/ru/yandex/yamblz/App.java b/app/src/main/java/ru/yandex/yamblz/App.java index e5f9972..23c0d19 100644 --- a/app/src/main/java/ru/yandex/yamblz/App.java +++ b/app/src/main/java/ru/yandex/yamblz/App.java @@ -2,12 +2,16 @@ import android.app.Application; import android.content.Context; +import android.os.Handler; +import android.os.Looper; import android.support.annotation.NonNull; import ru.yandex.yamblz.developer_settings.DevMetricsProxy; import ru.yandex.yamblz.developer_settings.DeveloperSettingsModel; import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.handler.StubCriticalSectionsHandler; import ru.yandex.yamblz.loader.CollageLoaderManager; +import ru.yandex.yamblz.loader.StubCollageLoader; import timber.log.Timber; public class App extends Application { @@ -34,8 +38,8 @@ public void onCreate() { devMetricsProxy.apply(); } - CollageLoaderManager.init(null); // add implementation - CriticalSectionsManager.init(null); // add implementation + CollageLoaderManager.init(new StubCollageLoader()); + CriticalSectionsManager.init(new StubCriticalSectionsHandler(new Handler(Looper.getMainLooper()))); } @NonNull diff --git a/app/src/main/java/ru/yandex/yamblz/Constants.java b/app/src/main/java/ru/yandex/yamblz/Constants.java new file mode 100644 index 0000000..b486f7b --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/Constants.java @@ -0,0 +1,12 @@ +package ru.yandex.yamblz; + +/** + * Created by Aleksandra on 24/07/16. + */ +public final class Constants { + + public static final String MOBILIZATION_URL = "http://download.cdn.yandex.net/mobilization-2016/artists.json"; + + private Constants() { + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsManager.java b/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsManager.java index 8a3d496..3c4daaa 100644 --- a/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsManager.java +++ b/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsManager.java @@ -1,8 +1,14 @@ package ru.yandex.yamblz.handler; +import android.os.Handler; +import android.os.Looper; + public class CriticalSectionsManager { - private static CriticalSectionsHandler sCriticalSectionsHandler; + private static volatile CriticalSectionsHandler sCriticalSectionsHandler; + + private CriticalSectionsManager() { + } public static void init(CriticalSectionsHandler criticalSectionsHandler) { sCriticalSectionsHandler = criticalSectionsHandler; @@ -10,7 +16,7 @@ public static void init(CriticalSectionsHandler criticalSectionsHandler) { public static CriticalSectionsHandler getHandler() { if (sCriticalSectionsHandler == null) { - sCriticalSectionsHandler = new StubCriticalSectionsHandler(); + sCriticalSectionsHandler = new StubCriticalSectionsHandler(new Handler(Looper.getMainLooper())); } return sCriticalSectionsHandler; } diff --git a/app/src/main/java/ru/yandex/yamblz/handler/StubCriticalSectionsHandler.java b/app/src/main/java/ru/yandex/yamblz/handler/StubCriticalSectionsHandler.java index 0af9646..4fb2884 100644 --- a/app/src/main/java/ru/yandex/yamblz/handler/StubCriticalSectionsHandler.java +++ b/app/src/main/java/ru/yandex/yamblz/handler/StubCriticalSectionsHandler.java @@ -1,39 +1,82 @@ package ru.yandex.yamblz.handler; +import android.os.Handler; + +import java.util.concurrent.CopyOnWriteArrayList; + public class StubCriticalSectionsHandler implements CriticalSectionsHandler { + private final Handler handler; + private final CopyOnWriteArrayList criticalSections = new CopyOnWriteArrayList<>(); + private final CopyOnWriteArrayList lowPriorityTasks = new CopyOnWriteArrayList<>(); + private final LowPriorityTaskExecutor executor = new LowPriorityTaskExecutor(); + + public StubCriticalSectionsHandler(Handler handler) { + this.handler = handler; + } + @Override public void startSection(int id) { - + if (!criticalSections.contains(id)) { + criticalSections.add(id); + handler.removeCallbacks(executor); + } } @Override public void stopSection(int id) { - + criticalSections.remove(Integer.valueOf(id)); + if (criticalSections.isEmpty()) { + handler.post(executor); + } } @Override public void stopSections() { - + criticalSections.clear(); + handler.post(executor); } @Override public void postLowPriorityTask(Task task) { - + if (criticalSections.isEmpty() && lowPriorityTasks.isEmpty()) { + lowPriorityTasks.add(task); + handler.post(executor); + } else { + lowPriorityTasks.add(task); + } } @Override public void postLowPriorityTaskDelayed(Task task, int delay) { - + lowPriorityTasks.add(task); } @Override public void removeLowPriorityTask(Task task) { - + lowPriorityTasks.remove(task); } @Override public void removeLowPriorityTasks() { + handler.removeCallbacks(executor); + lowPriorityTasks.clear(); + } + + public class LowPriorityTaskExecutor implements Runnable { + @Override + public void run() { + executeLowPriorityTask(); + } + + public void executeLowPriorityTask() { + Task currentTask; + while (criticalSections.isEmpty() && !lowPriorityTasks.isEmpty()) { + currentTask = lowPriorityTasks.remove(0); + currentTask.run(); + } + } } + } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoaderManager.java b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoaderManager.java index ef00d00..096f3a3 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoaderManager.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoaderManager.java @@ -2,7 +2,10 @@ public class CollageLoaderManager { - private static CollageLoader sCollageLoader; + private static volatile CollageLoader sCollageLoader; + + private CollageLoaderManager() { + } public static void init(CollageLoader collageLoader) { sCollageLoader = collageLoader; diff --git a/app/src/main/java/ru/yandex/yamblz/loader/CollageStrategy.java b/app/src/main/java/ru/yandex/yamblz/loader/CollageStrategy.java index d81d52d..3ae0317 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/CollageStrategy.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/CollageStrategy.java @@ -6,5 +6,7 @@ public interface CollageStrategy { + int amountOfImagesNeeded(); + Bitmap create(List bitmaps); } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/FourImagesCollageStrategy.java b/app/src/main/java/ru/yandex/yamblz/loader/FourImagesCollageStrategy.java new file mode 100644 index 0000000..6262276 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/FourImagesCollageStrategy.java @@ -0,0 +1,44 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.util.Log; + +import java.util.List; + +/** + * Created by Aleksandra on 24/07/16. + */ +public class FourImagesCollageStrategy implements CollageStrategy { + public static final String DEBUG_TAG = FourImagesCollageStrategy.class.getName(); + + @Override + public int amountOfImagesNeeded() { + return 4; + } + + @Override + public Bitmap create(List bitmaps) { + Log.d(DEBUG_TAG, "in create collage"); + + Bitmap result; + + if (bitmaps.size() >= 4) { + result = Bitmap.createBitmap(600, 600, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(result); + canvas.drawBitmap(bitmaps.get(0), 0, 0, null); + canvas.drawBitmap(bitmaps.get(1), 0, 300, null); + canvas.drawBitmap(bitmaps.get(2), 300, 0, null); + canvas.drawBitmap(bitmaps.get(3), 300, 300, null); + canvas.save(); + } else { + result = Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(result); + canvas.drawBitmap(bitmaps.get(0), 0, 0, null); + canvas.save(); + } + + return result; + } + +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/GenreLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/GenreLoader.java new file mode 100644 index 0000000..d7648df --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/GenreLoader.java @@ -0,0 +1,87 @@ +package ru.yandex.yamblz.loader; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import ru.yandex.yamblz.Constants; +import ru.yandex.yamblz.model.ArtistInfo; +import ru.yandex.yamblz.model.Genre; + +/** + * Created by Aleksandra on 25/07/16. + */ +public class GenreLoader extends AsyncTaskLoader> { + public static final String DEBUG_TAG = GenreLoader.class.getName(); + + private OkHttpClient client = new OkHttpClient(); + private Gson gson = new Gson(); + private TypeToken> artists = new TypeToken>() { + }; + + public GenreLoader(Context context) { + super(context); + } + + @Override + public List loadInBackground() { + Request request = new Request.Builder() + .url(Constants.MOBILIZATION_URL) + .build(); + + Response response; + try { + response = client.newCall(request).execute(); + ResponseBody responseBody = response.body(); + + List artistInfoList = gson.fromJson(responseBody.charStream(), artists.getType()); + responseBody.close(); + + Map genres = new HashMap<>(); + for (ArtistInfo a : artistInfoList) { + for (String g : a.getGenres()) { + if (genres.containsKey(g)) { + genres.get(g).getUrls().add(a.getCover().getSmall()); + } else { + List list = new ArrayList<>(); + list.add(a.getCover().getSmall()); + genres.put(g, new Genre(list, g)); + } + } + } + List result = new ArrayList<>(genres.size()); + + for (Map.Entry entry : genres.entrySet()) { + result.add(entry.getValue()); + } + + for (Genre g : result) { + Log.d(DEBUG_TAG, "" + g.toString()); + } + + return result; + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + forceLoad(); + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/ImageTarget.java b/app/src/main/java/ru/yandex/yamblz/loader/ImageTarget.java index 9a8be2b..246e0ef 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/ImageTarget.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/ImageTarget.java @@ -2,7 +2,14 @@ import android.graphics.Bitmap; +import ru.yandex.yamblz.handler.Task; +import rx.Subscription; + public interface ImageTarget { void onLoadBitmap(Bitmap bitmap); + + void setSubscription(Subscription subscription); + + void setTask(Task task); } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/ImageViewImageTarget.java b/app/src/main/java/ru/yandex/yamblz/loader/ImageViewImageTarget.java new file mode 100644 index 0000000..7174194 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/ImageViewImageTarget.java @@ -0,0 +1,48 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.util.Log; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; + +import ru.yandex.yamblz.R; +import ru.yandex.yamblz.handler.Task; +import rx.Subscription; + +/** + * Created by Aleksandra on 27/07/16. + */ +public class ImageViewImageTarget implements ImageTarget { + private WeakReference reference; + + public ImageViewImageTarget(WeakReference reference) { + this.reference = reference; + } + + @Override + public void onLoadBitmap(Bitmap bitmap) { + final ImageView iv = reference.get(); + if (iv != null) { + Log.d("qq", iv.getParent().toString()); + iv.setImageBitmap(bitmap); + iv.invalidate(); + } + } + + @Override + public void setSubscription(Subscription subscription) { + final ImageView iv = reference.get(); + if (iv != null) { + iv.setTag(R.id.tag_subscription, subscription); + } + } + + @Override + public void setTask(Task task) { + final ImageView iv = reference.get(); + if (iv != null) { + iv.setTag(R.id.tag_task, task); + } + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java index 1dc051b..3bb97a2 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/StubCollageLoader.java @@ -1,31 +1,127 @@ package ru.yandex.yamblz.loader; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.widget.ImageView; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.LinkedList; import java.util.List; +import java.util.concurrent.Executors; + +import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.handler.Task; +import rx.Observable; +import rx.Scheduler; +import rx.Subscriber; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action2; +import rx.schedulers.Schedulers; public class StubCollageLoader implements CollageLoader { + public static final String DEBUG_TAG = StubCollageLoader.class.getName(); + + private static final Scheduler SCHEDULER = Schedulers.from(Executors.newFixedThreadPool(10)); @Override public void loadCollage(List urls, ImageView imageView) { - + loadCollage(urls, imageView, new FourImagesCollageStrategy()); } @Override public void loadCollage(List urls, ImageTarget imageTarget) { - + loadCollage(urls, imageTarget, new FourImagesCollageStrategy()); } @Override - public void loadCollage(List urls, ImageView imageView, - CollageStrategy collageStrategy) { - + public void loadCollage(List urls, ImageView imageView, CollageStrategy collageStrategy) { + loadCollage(urls, new ImageViewImageTarget(new WeakReference(imageView)), collageStrategy); } @Override public void loadCollage(List urls, ImageTarget imageTarget, CollageStrategy collageStrategy) { + int n = Math.min(urls.size(), collageStrategy.amountOfImagesNeeded()); + urls = urls.subList(0, n); + + Subscription subscription = Observable.from(urls) + .flatMap(s -> Observable.just(s) + .observeOn(SCHEDULER) + .map(this::loadBitmapFromUrl)) + .collect(LinkedList::new, new Action2, Bitmap>() { + @Override + public void call(LinkedList bitmaps, Bitmap bitmap) { + bitmaps.add(bitmap); + } + }) + .map(collageStrategy::create) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Subscriber() { + @Override + public void onCompleted() { + } + @Override + public void onError(Throwable e) { + + } + + @Override + public void onNext(Bitmap collage) { + Task task = new ImageViewSetter(imageTarget, collage); + imageTarget.setTask(task); + CriticalSectionsManager.getHandler() + .postLowPriorityTask(task); + } + }); + imageTarget.setSubscription(subscription); + } + + protected Bitmap loadBitmapFromUrl(String stringUrl) { + Bitmap bitmap = null; + HttpURLConnection connection = null; + InputStream inputStream = null; + try { + URL url = new URL(stringUrl); + connection = (HttpURLConnection) url.openConnection(); + connection.setDoInput(true); + connection.connect(); + inputStream = connection.getInputStream(); + bitmap = BitmapFactory.decodeStream(inputStream); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (connection != null) { + connection.disconnect(); + } + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + return bitmap; } + public class ImageViewSetter implements Task { + private ImageTarget target; + private Bitmap collage; + + public ImageViewSetter(ImageTarget target, Bitmap collage) { + this.target = target; + this.collage = collage; + } + + @Override + public void run() { + target.onLoadBitmap(collage); + } + } } diff --git a/app/src/main/java/ru/yandex/yamblz/model/ArtistInfo.java b/app/src/main/java/ru/yandex/yamblz/model/ArtistInfo.java new file mode 100644 index 0000000..9901c52 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/model/ArtistInfo.java @@ -0,0 +1,144 @@ +package ru.yandex.yamblz.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.List; + +/** + * Model + * + * @author Aleksandra Bobrova + */ +public class ArtistInfo implements Parcelable { + public static final Creator CREATOR = new Creator() { + @Override + public ArtistInfo createFromParcel(Parcel in) { + return new ArtistInfo(in); + } + + @Override + public ArtistInfo[] newArray(int size) { + return new ArtistInfo[size]; + } + }; + private long id; + private String name; + private List genres; + private long tracks; + private long albums; + private String link; + private String description; + private Cover cover; + + public ArtistInfo() { + } + + protected ArtistInfo(Parcel in) { + id = in.readLong(); + name = in.readString(); + genres = in.createStringArrayList(); + tracks = in.readLong(); + albums = in.readLong(); + link = in.readString(); + description = in.readString(); + cover = new Cover(); + cover.setBig(in.readString()); + cover.setSmall(in.readString()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(id); + dest.writeString(name); + dest.writeStringList(genres); + dest.writeLong(tracks); + dest.writeLong(albums); + dest.writeString(link); + dest.writeString(description); + dest.writeString(cover.getBig()); + dest.writeString(cover.getSmall()); + } + + @Override + public String toString() { + return "ArtistInfo{" + + "id=" + id + + ", name='" + name + '\'' + + ", genres=" + genres + + ", albums=" + albums + + ", link='" + link + '\'' + + ", description='" + description + '\'' + + ", cover=" + cover + + '}'; + } + + public long getId() { + return id; + } + + public String getLink() { + return link; + } + + public String getName() { + return name; + } + + public List getGenres() { + return genres; + } + + public Cover getCover() { + return cover; + } + + public long getAlbums() { + return albums; + } + + public String getDescription() { + return description; + } + + public long getTracks() { + return tracks; + } + + public void setId(long id) { + this.id = id; + } + + public void setName(String name) { + this.name = name; + } + + public void setGenres(List genres) { + this.genres = genres; + } + + public void setTracks(long tracks) { + this.tracks = tracks; + } + + public void setAlbums(long albums) { + this.albums = albums; + } + + public void setLink(String link) { + this.link = link; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setCover(Cover cover) { + this.cover = cover; + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/model/Cover.java b/app/src/main/java/ru/yandex/yamblz/model/Cover.java new file mode 100644 index 0000000..3937838 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/model/Cover.java @@ -0,0 +1,28 @@ +package ru.yandex.yamblz.model; + +/** + * Created by Aleksandra on 20/07/16. + */ +public class Cover { + private String small; + private String big; + + public Cover() { + } + + public String getSmall() { + return small; + } + + public String getBig() { + return big; + } + + public void setSmall(String small) { + this.small = small; + } + + public void setBig(String big) { + this.big = big; + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/model/Genre.java b/app/src/main/java/ru/yandex/yamblz/model/Genre.java new file mode 100644 index 0000000..838bd57 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/model/Genre.java @@ -0,0 +1,38 @@ +package ru.yandex.yamblz.model; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by Aleksandra on 25/07/16. + */ +public class Genre { + private List urls; + private String name; + + public Genre(List urls, String name) { + this.urls = urls; + this.name = name; + } + + public List getUrls() { + return urls; + } + + public String getName() { + return name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public String toString() { + return "Genre{" + + "urls=" + Arrays.deepToString(urls.toArray()) + + ", name='" + name + '\'' + + '}'; + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/ui/MyScrollListener.java b/app/src/main/java/ru/yandex/yamblz/ui/MyScrollListener.java new file mode 100644 index 0000000..dd45652 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/ui/MyScrollListener.java @@ -0,0 +1,34 @@ +package ru.yandex.yamblz.ui; + +import android.support.v7.widget.RecyclerView; +import android.util.Log; + +import ru.yandex.yamblz.handler.CriticalSectionsManager; + +/** + * Created by Aleksandra on 26/07/16. + */ +public class MyScrollListener extends RecyclerView.OnScrollListener { + public static final String DEBUG_TAG = MyScrollListener.class.getName(); + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + + switch (newState) { + case RecyclerView.SCROLL_STATE_DRAGGING: + CriticalSectionsManager.getHandler().startSection(0); + Log.d(DEBUG_TAG, "In scroll state dragging"); + break; + case RecyclerView.SCROLL_STATE_SETTLING: + Log.d(DEBUG_TAG, "In scroll state settling"); + break; + case RecyclerView.SCROLL_STATE_IDLE: + Log.d(DEBUG_TAG, "In scroll state idle"); + CriticalSectionsManager.getHandler().stopSection(0); + break; + default: + break; + } + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreListAdapter.java b/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreListAdapter.java new file mode 100644 index 0000000..9e21627 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreListAdapter.java @@ -0,0 +1,100 @@ +package ru.yandex.yamblz.ui.adapters; + +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; +import ru.yandex.yamblz.R; +import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.handler.Task; +import ru.yandex.yamblz.loader.CollageLoaderManager; +import ru.yandex.yamblz.loader.FourImagesCollageStrategy; +import ru.yandex.yamblz.model.Genre; +import rx.Subscription; + +/** + * Created by Aleksandra on 25/07/16. + */ +public class GenreListAdapter extends RecyclerView.Adapter { + public static final String DEBUG_TAG = GenreListAdapter.class.getName(); + private List dataset = new ArrayList<>(); + + + @Override + public GenreViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_genre, parent, false); + return new GenreViewHolder(v); + } + + @Override + public void onBindViewHolder(GenreViewHolder holder, int position) { + Log.d(DEBUG_TAG, "On bind" + holder.toString()); + + Subscription subscription = (Subscription) holder.image.getTag(R.id.tag_subscription); + if (subscription != null && !subscription.isUnsubscribed()) { + subscription.unsubscribe(); + } + + Genre genre = dataset.get(position); + holder.name.setText(genre.getName()); + Log.d(DEBUG_TAG, Arrays.deepToString(genre.getUrls().toArray())); + + holder.image.setImageDrawable(null); + holder.image.invalidate(); + CollageLoaderManager.getLoader() + .loadCollage(genre.getUrls(), holder.image, new FourImagesCollageStrategy()); + } + + @Override + public void onViewRecycled(GenreViewHolder holder) { + super.onViewRecycled(holder); + Subscription subscription = (Subscription) holder.image.getTag(R.id.tag_subscription); + if (subscription != null) { + subscription.unsubscribe(); + } + Task task = (Task) holder.image.getTag(R.id.tag_task); + if (task != null) { + CriticalSectionsManager.getHandler().removeLowPriorityTask(task); + } + Log.d(DEBUG_TAG, "Recycled" + holder.toString()); + } + + @Override + public void onViewAttachedToWindow(GenreViewHolder holder) { + super.onViewAttachedToWindow(holder); + } + + + public void setDataset(List dataset) { + this.dataset = dataset; + notifyDataSetChanged(); + } + + @Override + public int getItemCount() { + return dataset != null ? dataset.size() : 0; + } + + public class GenreViewHolder extends RecyclerView.ViewHolder { + @BindView(R.id.text_view_genre) + TextView name; + @BindView(R.id.image_view_genre) + ImageView image; + + public GenreViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + } + +} diff --git a/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java b/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java index d46490f..712259f 100644 --- a/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java +++ b/app/src/main/java/ru/yandex/yamblz/ui/fragments/ContentFragment.java @@ -3,16 +3,57 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; import ru.yandex.yamblz.R; +import ru.yandex.yamblz.loader.GenreLoader; +import ru.yandex.yamblz.model.Genre; +import ru.yandex.yamblz.ui.MyScrollListener; +import ru.yandex.yamblz.ui.adapters.GenreListAdapter; + +public class ContentFragment extends BaseFragment implements LoaderManager.LoaderCallbacks> { + + @BindView(R.id.recycler_view) + RecyclerView recyclerView; + + private GenreListAdapter adapter = new GenreListAdapter(); -public class ContentFragment extends BaseFragment { @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_content, container, false); + View v = inflater.inflate(R.layout.fragment_content, container, false); + ButterKnife.bind(this, v); + + recyclerView.setAdapter(adapter); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + recyclerView.addOnScrollListener(new MyScrollListener()); + + getLoaderManager().initLoader(1, null, this); + return v; + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new GenreLoader(getActivity()); + } + + @Override + public void onLoadFinished(Loader> loader, List data) { + adapter.setDataset(data); + } + + @Override + public void onLoaderReset(Loader> loader) { + } } diff --git a/app/src/main/res/layout/fragment_content.xml b/app/src/main/res/layout/fragment_content.xml index 81016ea..92f7be0 100644 --- a/app/src/main/res/layout/fragment_content.xml +++ b/app/src/main/res/layout/fragment_content.xml @@ -3,12 +3,9 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:layout_height="match_parent"/> \ No newline at end of file diff --git a/app/src/main/res/layout/view_genre.xml b/app/src/main/res/layout/view_genre.xml new file mode 100644 index 0000000..a285f4d --- /dev/null +++ b/app/src/main/res/layout/view_genre.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml new file mode 100644 index 0000000..e2d3cb3 --- /dev/null +++ b/app/src/main/res/values/ids.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/dependencies.gradle b/dependencies.gradle index d9cb375..28aa8e9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -23,6 +23,10 @@ ext.versions = [ supportLibs : '23.1.1', butterKnife : '8.0.1', timber : '4.1.2', + rxjava : '1.1.6', + rxandroid : '1.2.1', + okhttp : '3.2.0', + gson : '2.6.2', espresso : '2.2.1', stetho : '1.3.1', @@ -52,37 +56,41 @@ ext.gradlePlugins = [ ] ext.libraries = [ - dagger : "com.google.dagger:dagger:$versions.dagger", - daggerCompiler : "com.google.dagger:dagger-compiler:$versions.dagger", + dagger : "com.google.dagger:dagger:$versions.dagger", + daggerCompiler : "com.google.dagger:dagger-compiler:$versions.dagger", - autoValue : "com.google.auto.value:auto-value:$versions.autoValue", + autoValue : "com.google.auto.value:auto-value:$versions.autoValue", - supportAnnotations : "com.android.support:support-annotations:$versions.supportLibs", - supportAppCompat : "com.android.support:appcompat-v7:$versions.supportLibs", - supportDesign : "com.android.support:design:$versions.supportLibs", - supportRecyclerView : "com.android.support:recyclerview-v7:$versions.supportLibs", - supportCardView : "com.android.support:cardview-v7:$versions.supportLibs", + supportAnnotations : "com.android.support:support-annotations:$versions.supportLibs", + supportAppCompat : "com.android.support:appcompat-v7:$versions.supportLibs", + supportDesign : "com.android.support:design:$versions.supportLibs", + supportRecyclerView: "com.android.support:recyclerview-v7:$versions.supportLibs", + supportCardView : "com.android.support:cardview-v7:$versions.supportLibs", - butterKnife : "com.jakewharton:butterknife:$versions.butterKnife", - butterKnifeCompiler : "com.jakewharton:butterknife-compiler:$versions.butterKnife", - timber : "com.jakewharton.timber:timber:$versions.timber", + butterKnife : "com.jakewharton:butterknife:$versions.butterKnife", + butterKnifeCompiler: "com.jakewharton:butterknife-compiler:$versions.butterKnife", + timber : "com.jakewharton.timber:timber:$versions.timber", // Developer Tools - stetho : "com.facebook.stetho:stetho:$versions.stetho", - leakCanary : "com.squareup.leakcanary:leakcanary-android:$versions.leakCanary", - tinyDancer : "com.github.brianPlummer:tinydancer:$versions.tinyDancer", - lynx : "com.github.pedrovgs:lynx:$versions.lynx", - devMetricsNoOp : "com.frogermcs.androiddevmetrics:androiddevmetrics-runtime-noop:$versions.androidDevMetricsGradlePlugin", - processPhoenix : "com.jakewharton:process-phoenix:$versions.processPhoenix", + stetho : "com.facebook.stetho:stetho:$versions.stetho", + leakCanary : "com.squareup.leakcanary:leakcanary-android:$versions.leakCanary", + tinyDancer : "com.github.brianPlummer:tinydancer:$versions.tinyDancer", + lynx : "com.github.pedrovgs:lynx:$versions.lynx", + devMetricsNoOp : "com.frogermcs.androiddevmetrics:androiddevmetrics-runtime-noop:$versions.androidDevMetricsGradlePlugin", + processPhoenix : "com.jakewharton:process-phoenix:$versions.processPhoenix", + rxjava : "io.reactivex:rxjava:$versions.rxjava", + rxandroid : "io.reactivex:rxandroid:$versions.rxandroid", + okhttp : "com.squareup.okhttp3:okhttp:$versions.okhttp", + gson : "com.google.code.gson:gson:$versions.gson", // Test dependencies - junit : "junit:junit:$versions.junit", - robolectric : "org.robolectric:robolectric:$versions.robolectric", - assertJ : "org.assertj:assertj-core:$versions.assertJ", - equalsVerifier : "nl.jqno.equalsverifier:equalsverifier:$versions.equalsVerifier", - mockitoCore : "org.mockito:mockito-core:$versions.mockito", - supportTestRunner : "com.android.support.test:runner:$versions.supportTestRunner", - supportTestRules : "com.android.support.test:rules:$versions.supportTestRunner", - espressoCore : "com.android.support.test.espresso:espresso-core:$versions.espresso", - espressoContrib : "com.android.support.test.espresso:espresso-contrib:$versions.espresso", + junit : "junit:junit:$versions.junit", + robolectric : "org.robolectric:robolectric:$versions.robolectric", + assertJ : "org.assertj:assertj-core:$versions.assertJ", + equalsVerifier : "nl.jqno.equalsverifier:equalsverifier:$versions.equalsVerifier", + mockitoCore : "org.mockito:mockito-core:$versions.mockito", + supportTestRunner : "com.android.support.test:runner:$versions.supportTestRunner", + supportTestRules : "com.android.support.test:rules:$versions.supportTestRunner", + espressoCore : "com.android.support.test.espresso:espresso-core:$versions.espresso", + espressoContrib : "com.android.support.test.espresso:espresso-contrib:$versions.espresso", ]