diff --git a/app/build.gradle b/app/build.gradle index 445372a..0d6d111 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -105,6 +105,21 @@ dependencies { compile libraries.lynx compile libraries.processPhoenix + // okhttp + compile 'com.squareup.okhttp3:okhttp:3.4.1' + compile 'com.squareup.okhttp3:logging-interceptor:3.4.1' + + // RxJava + compile 'io.reactivex:rxjava:1.1.8' + + // RxAndroid + compile 'io.reactivex:rxandroid:1.2.1' + + // retrofit + stuff + compile 'com.squareup.retrofit2:retrofit:2.1.0' + compile 'com.squareup.retrofit2:converter-gson:2.1.0' + compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0' + testCompile libraries.junit testCompile libraries.robolectric testCompile libraries.assertJ @@ -121,6 +136,7 @@ dependencies { exclude module: 'recyclerview-v7' exclude module: 'support-v4' } + compile 'javax.annotation:javax.annotation-api:1.2' } 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..fcefd03 100644 --- a/app/src/main/java/ru/yandex/yamblz/App.java +++ b/app/src/main/java/ru/yandex/yamblz/App.java @@ -7,7 +7,9 @@ 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 +36,8 @@ public void onCreate() { devMetricsProxy.apply(); } - CollageLoaderManager.init(null); // add implementation - CriticalSectionsManager.init(null); // add implementation + CollageLoaderManager.init(new StubCollageLoader()); // add implementation + CriticalSectionsManager.init(new StubCriticalSectionsHandler()); // add implementation } @NonNull diff --git a/app/src/main/java/ru/yandex/yamblz/api/YandexArtistApi.java b/app/src/main/java/ru/yandex/yamblz/api/YandexArtistApi.java new file mode 100644 index 0000000..573bc1b --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/api/YandexArtistApi.java @@ -0,0 +1,18 @@ +package ru.yandex.yamblz.api; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.http.GET; + +/** + * Created by user on 01.08.16. + */ + +public interface YandexArtistApi { + + String URL = "http://download.cdn.yandex.net/"; + + @GET("mobilization-2016/artists.json") + Call> getListArtist(); +} diff --git a/app/src/main/java/ru/yandex/yamblz/api/YandexArtistResponse.java b/app/src/main/java/ru/yandex/yamblz/api/YandexArtistResponse.java new file mode 100644 index 0000000..22ac385 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/api/YandexArtistResponse.java @@ -0,0 +1,165 @@ +package ru.yandex.yamblz.api; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Generated; + +/** + * Created by user on 01.08.16. + */ +@Generated("org.jsonschema2pojo") +public class YandexArtistResponse { + @SerializedName("id") + @Expose + private int id; + @SerializedName("name") + @Expose + private String name; + @SerializedName("genres") + @Expose + private List genres = new ArrayList(); + @SerializedName("tracks") + @Expose + private int tracks; + @SerializedName("albums") + @Expose + private int albums; + @SerializedName("link") + @Expose + private String link; + @SerializedName("description") + @Expose + private String description; + @SerializedName("cover") + @Expose + private Cover cover; + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public List getGenres() { + return genres; + } + + public int getTracks() { + return tracks; + } + + public int getAlbums() { + return albums; + } + + public String getLink() { + return link; + } + + public String getDescription() { + return description; + } + + public Cover getCover() { + return cover; + } + + @Override + public String toString() { + return "YandexArtistResponse{" + + "id=" + id + + ", name='" + name + '\'' + + ", genres=" + genres + + ", tracks=" + tracks + + ", albums=" + albums + + ", link='" + link + '\'' + + ", description='" + description + '\'' + + ", cover=" + cover + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + YandexArtistResponse that = (YandexArtistResponse) o; + + if (id != that.id) return false; + if (tracks != that.tracks) return false; + if (albums != that.albums) return false; + if (!name.equals(that.name)) return false; + if (!genres.equals(that.genres)) return false; + if (!link.equals(that.link)) return false; + if (!description.equals(that.description)) return false; + if (!cover.equals(that.cover)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = id; + result = 31 * result + name.hashCode(); + result = 31 * result + genres.hashCode(); + result = 31 * result + tracks; + result = 31 * result + albums; + result = 31 * result + link.hashCode(); + result = 31 * result + description.hashCode(); + result = 31 * result + cover.hashCode(); + return result; + } + + @Generated("org.jsonschema2pojo") + public class Cover { + + @SerializedName("small") + @Expose + private String small; + @SerializedName("big") + @Expose + private String big; + + public String getSmall() { + return small; + } + + public String getBig() { + return big; + } + + @Override + public String toString() { + return "Cover{" + + "small='" + small + '\'' + + ", big='" + big + '\'' + + '}'; + } + + @Override + public int hashCode() { + int result = small.hashCode(); + result = 31 * result + big.hashCode(); + return result; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Cover cover = (Cover) o; + + if (!small.equals(cover.small)) return false; + if (!big.equals(cover.big)) return false; + + return true; + } + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsHandler.java b/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsHandler.java index 8b8cc56..81209c4 100644 --- a/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsHandler.java +++ b/app/src/main/java/ru/yandex/yamblz/handler/CriticalSectionsHandler.java @@ -8,9 +8,9 @@ public interface CriticalSectionsHandler { void stopSections(); - void postLowPriorityTask(Task task); + Task postLowPriorityTask(Task task); - void postLowPriorityTaskDelayed(Task task, int delay); + Task postLowPriorityTaskDelayed(Task task, int delay); void removeLowPriorityTask(Task task); 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..a75772c 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,75 @@ package ru.yandex.yamblz.handler; +import android.os.Handler; +import android.os.Looper; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; + +import timber.log.Timber; + public class StubCriticalSectionsHandler implements CriticalSectionsHandler { + private Handler mainHandler; + private Queue taskQueue; + private Set criticalSections; + + public StubCriticalSectionsHandler() { + mainHandler = new Handler(Looper.getMainLooper()); + taskQueue = new ConcurrentLinkedQueue<>(); + criticalSections = new HashSet<>(); + } + @Override public void startSection(int id) { - + criticalSections.add(id); } @Override public void stopSection(int id) { - + criticalSections.remove(id); + if (criticalSections.isEmpty()) { + startLowPriorityTask(); + } } @Override public void stopSections() { - + criticalSections.clear(); + startLowPriorityTask(); } @Override - public void postLowPriorityTask(Task task) { - + public Task postLowPriorityTask(Task task) { + taskQueue.add(task); + startLowPriorityTask(); + return task; } @Override - public void postLowPriorityTaskDelayed(Task task, int delay) { - + public Task postLowPriorityTaskDelayed(Task task, int delay) { + mainHandler.postDelayed(() -> postLowPriorityTask(task), delay); + return task; } @Override public void removeLowPriorityTask(Task task) { - + taskQueue.remove(task); } @Override public void removeLowPriorityTasks() { + taskQueue.clear(); + } + private void startLowPriorityTask() { + Timber.d("low priority size = " + taskQueue.size()); + while (!taskQueue.isEmpty() && criticalSections.isEmpty()) { + Task task = taskQueue.poll(); + Timber.d("start task"); + mainHandler.post(() -> task.run()); + } } } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java index dad5b76..152d256 100644 --- a/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java +++ b/app/src/main/java/ru/yandex/yamblz/loader/CollageLoader.java @@ -4,14 +4,16 @@ import java.util.List; +import rx.Subscription; + public interface CollageLoader { - void loadCollage(List urls, ImageView imageView); + Subscription loadCollage(List urls, ImageView imageView); - void loadCollage(List urls, ImageTarget imageTarget); + Subscription loadCollage(List urls, ImageTarget imageTarget); - void loadCollage(List urls, ImageView imageView, CollageStrategy collageStrategy); + Subscription loadCollage(List urls, ImageView imageView, CollageStrategy collageStrategy); - void loadCollage(List urls, ImageTarget imageTarget, CollageStrategy collageStrategy); + Subscription loadCollage(List urls, ImageTarget imageTarget, CollageStrategy collageStrategy); } diff --git a/app/src/main/java/ru/yandex/yamblz/loader/MyCollageStrategy.java b/app/src/main/java/ru/yandex/yamblz/loader/MyCollageStrategy.java new file mode 100644 index 0000000..8c04429 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/MyCollageStrategy.java @@ -0,0 +1,82 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; + +import java.util.List; + +/** + * Created by SerG3z on 02.08.16. + */ + +public class MyCollageStrategy implements CollageStrategy { + + @Override + public Bitmap create(List bitmaps) { + int size = bitmaps.size(); + int sqr = (int) Math.sqrt(size); + + Bitmap bitmap = Bitmap.createBitmap(600, 600, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + if (size >= 4) { + if (sqr > 10) { + sqr = 10; + } + int width = bitmap.getWidth() / sqr; + int index = 0; + Rect rect; + for (int i = 0; i < sqr; i++) { + for (int j = 0; j < sqr; j++) { +// first version +// canvas.drawBitmap(getResizedBitmap(bitmaps.get(index++), width, width), j * width, i * width, null); + rect = new Rect(j * width, i * width, j * width + width, i * width + width); + canvas.drawBitmap(bitmaps.get(index++), null, rect, null); + } + } + canvas.save(); + return bitmap; + } else if (size == 3) { + canvas.drawBitmap(bitmaps.get(0), null, new Rect(0, 0, 298, 298), null); + canvas.drawBitmap(bitmaps.get(1), null, new Rect(302, 0, 600, 298), null); + canvas.drawBitmap(bitmaps.get(2), null, new Rect(150, 302, 450, 600), null); + canvas.save(); + return bitmap; + } else if (size == 2) { + Paint paint = new Paint(); + paint.setColor(Color.WHITE); + canvas.drawBitmap(bitmaps.get(0), null, new Rect(0, 0, 600, 600), null); + canvas.drawRect(new Rect(300, 300, 600, 600), paint); //for beauty + canvas.drawBitmap(bitmaps.get(1), null, new Rect(305, 305, 595, 595), null); + canvas.save(); + return bitmap; + } else { + canvas.drawBitmap(bitmaps.get(0), 0, 0, null); + canvas.save(); + return bitmaps.get(0); + } + } +// +// first version +// private Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) { +// int width = bm.getWidth(); +// int height = bm.getHeight(); +// float scaleWidth = ((float) newWidth) / width; +// float scaleHeight = ((float) newHeight) / height; +// Timber.d("scaleW = " + scaleWidth); +// Timber.d("scaleH = " + scaleHeight); +// if (scaleHeight >= 1.0 && scaleWidth >= 1.0) { +// return bm; +// } +// Matrix matrix = new Matrix(); +// matrix.postScale(scaleWidth, scaleHeight); +// Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); +// if (bm != null && !bm.isRecycled()) { +// bm.recycle(); +// bm = null; +// } +// return resizedBitmap; +// } +} diff --git a/app/src/main/java/ru/yandex/yamblz/loader/MyImageViewTarget.java b/app/src/main/java/ru/yandex/yamblz/loader/MyImageViewTarget.java new file mode 100644 index 0000000..ee5f79f --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/loader/MyImageViewTarget.java @@ -0,0 +1,26 @@ +package ru.yandex.yamblz.loader; + +import android.graphics.Bitmap; +import android.widget.ImageView; + +import java.lang.ref.WeakReference; + +/** + * Created by SerG3z on 02.08.16. + */ + +public class MyImageViewTarget implements ImageTarget { + private final WeakReference imageViewWeakReference; + + public MyImageViewTarget(ImageView imageView) { + imageViewWeakReference = new WeakReference<>(imageView); + } + + @Override + public void onLoadBitmap(Bitmap bitmap) { + ImageView imageView = imageViewWeakReference.get(); + if (imageView != null) { + imageView.setImageBitmap(bitmap); + } + } +} 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..9619e7f 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,69 @@ package ru.yandex.yamblz.loader; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.LruCache; import android.widget.ImageView; +import java.net.URL; import java.util.List; -public class StubCollageLoader implements CollageLoader { +import rx.Observable; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; - @Override - public void loadCollage(List urls, ImageView imageView) { +public class StubCollageLoader implements CollageLoader { + private LruCache, Bitmap> cache; + public StubCollageLoader() { + final int maxMemory = (int) (Runtime.getRuntime().maxMemory()); + final int cacheSize = maxMemory / 8; + cache = new LruCache<>(cacheSize); } @Override - public void loadCollage(List urls, ImageTarget imageTarget) { - + public Subscription loadCollage(List urls, ImageView imageView) { + return loadCollage(urls, new MyImageViewTarget(imageView), new MyCollageStrategy()); } @Override - public void loadCollage(List urls, ImageView imageView, - CollageStrategy collageStrategy) { - + public Subscription loadCollage(List urls, ImageTarget imageTarget) { + return loadCollage(urls, imageTarget, new MyCollageStrategy()); } @Override - public void loadCollage(List urls, ImageTarget imageTarget, - CollageStrategy collageStrategy) { + public Subscription loadCollage(List urls, ImageView imageView, + CollageStrategy collageStrategy) { + return loadCollage(urls, new MyImageViewTarget(imageView), collageStrategy); } + + @Override + public Subscription loadCollage(List urls, ImageTarget imageTarget, + CollageStrategy collageStrategy) { + return Observable + .from(urls) + .take(100) + .flatMap(s -> { + if (cache.get(urls) == null) { + return Observable.fromCallable(() -> BitmapFactory.decodeStream(new URL(s).openStream())); + } else + return Observable.empty(); + }) + .toList() + .map(bitmaps -> { + if (cache.get(urls) == null) { + Bitmap bitmap = collageStrategy.create(bitmaps); + cache.put(urls, bitmap); + return bitmap; + } else { + return cache.get(urls); + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe((imageTarget::onLoadBitmap)); + } } diff --git a/app/src/main/java/ru/yandex/yamblz/models/Genre.java b/app/src/main/java/ru/yandex/yamblz/models/Genre.java new file mode 100644 index 0000000..c2ed623 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/models/Genre.java @@ -0,0 +1,106 @@ +package ru.yandex.yamblz.models; + +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.List; + +import ru.yandex.yamblz.api.YandexArtistResponse; + +/** + * Created by SerG3z on 02.08.16. + */ + +public class Genre implements Comparable, Parcelable { + private String genre; + private List listArtist; + private List imageUrls; + + public Genre(String genreStr) { + genre = genreStr; + listArtist = new ArrayList<>(); + imageUrls = new ArrayList<>(); + } + + protected Genre(Parcel in) { + genre = in.readString(); + listArtist = in.createStringArrayList(); + imageUrls = in.createStringArrayList(); + } + + public static final Creator CREATOR = new Creator() { + @Override + public Genre createFromParcel(Parcel in) { + return new Genre(in); + } + + @Override + public Genre[] newArray(int size) { + return new Genre[size]; + } + }; + + public String getGenre() { + return genre; + } + + public List getListArtist() { + return listArtist; + } + + public List getImageUrls() { + return imageUrls; + } + + @Override + public String toString() { + return "Genre{" + + "genre='" + genre + '\'' + + ", listArtist=" + listArtist + + ", imageUrls=" + imageUrls + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Genre genre1 = (Genre) o; + + return genre.equals(genre1.genre) && listArtist.equals(genre1.listArtist) && imageUrls.equals(genre1.imageUrls); + + } + + @Override + public int hashCode() { + int result = genre.hashCode(); + result = 31 * result + listArtist.hashCode(); + result = 31 * result + imageUrls.hashCode(); + return result; + } + + @Override + public int compareTo(@NonNull Genre another) { + return genre.compareToIgnoreCase(another.genre); + } + + public void appendArtist(YandexArtistResponse yandexArtistResponse) { + imageUrls.add(yandexArtistResponse.getCover().getSmall()); + listArtist.add(yandexArtistResponse.getName()); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(genre); + dest.writeStringList(listArtist); + dest.writeStringList(imageUrls); + } +} diff --git a/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreRecyclerViewAdapter.java b/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreRecyclerViewAdapter.java new file mode 100644 index 0000000..a528694 --- /dev/null +++ b/app/src/main/java/ru/yandex/yamblz/ui/adapters/GenreRecyclerViewAdapter.java @@ -0,0 +1,113 @@ +package ru.yandex.yamblz.ui.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import java.util.ArrayList; +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.MyCollageStrategy; +import ru.yandex.yamblz.loader.MyImageViewTarget; +import ru.yandex.yamblz.models.Genre; +import rx.Subscription; + +/** + * Created by SerG3z on 02.08.16. + */ + +public class GenreRecyclerViewAdapter extends RecyclerView.Adapter { + + private List genreList; + + public GenreRecyclerViewAdapter() { + genreList = new ArrayList<>(); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_view, parent, false)); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + holder.bind(position); + } + + @Override + public int getItemCount() { + return genreList.size(); + } + + public void addAllData(List tmpListGenre) { + genreList.addAll(tmpListGenre); + notifyDataSetChanged(); + } + + public Genre getItem(int position) { + return genreList.get(position); + } + + @Override + public void onViewRecycled(ViewHolder holder) { + super.onViewRecycled(holder); + Subscription subscription = holder.getSubscription(); + if (subscription != null) { + subscription.unsubscribe(); + } + Task task = holder.getTask(); + if (task != null) { + CriticalSectionsManager.getHandler().removeLowPriorityTask(task); + } + } + + class ViewHolder extends RecyclerView.ViewHolder { + + @BindView(R.id.genres_image_view) + ImageView genreImageView; + @BindView(R.id.artists_text_view) + TextView artistList; + @BindView(R.id.genres_text_view) + TextView genreTextView; + @BindView(R.id.progress_bar) + ProgressBar progressBar; + private Subscription subscription; + private Task task; + + ViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + } + + void bind(int position) { + Genre genre = getItem(position); + genreImageView.setImageBitmap(null); + genreTextView.setText(genre.getGenre()); + artistList.setText(genre.getListArtist().toString()); + + task = CriticalSectionsManager.getHandler().postLowPriorityTask(() -> + subscription = CollageLoaderManager + .getLoader() + .loadCollage(genre.getImageUrls(), + new MyImageViewTarget(genreImageView), new MyCollageStrategy())); + } + + Subscription getSubscription() { + return subscription; + } + + Task getTask() { + return task; + } + } +} 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..9446c55 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 @@ -1,18 +1,170 @@ package ru.yandex.yamblz.ui.fragments; import android.os.Bundle; +import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.support.v7.widget.OrientationHelper; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import butterknife.BindView; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; +import ru.yandex.yamblz.BuildConfig; import ru.yandex.yamblz.R; +import ru.yandex.yamblz.api.YandexArtistApi; +import ru.yandex.yamblz.api.YandexArtistResponse; +import ru.yandex.yamblz.handler.CriticalSectionsHandler; +import ru.yandex.yamblz.handler.CriticalSectionsManager; +import ru.yandex.yamblz.models.Genre; +import ru.yandex.yamblz.ui.adapters.GenreRecyclerViewAdapter; +import rx.Observable; +import rx.Single; +import rx.android.schedulers.AndroidSchedulers; +import rx.schedulers.Schedulers; public class ContentFragment extends BaseFragment { + + private static final String TAG_SAVE_ARRAY = "save array"; + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + private YandexArtistApi artistApi; + private List genreList; + private GenreRecyclerViewAdapter adapter; + @NonNull @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_content, container, false); } + + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + adapter = new GenreRecyclerViewAdapter(); + recyclerView.setAdapter(adapter); +// GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 2); +// recyclerView.setLayoutManager(gridLayoutManager); + + StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(2, OrientationHelper.VERTICAL); + recyclerView.setLayoutManager(staggeredGridLayoutManager); + genreList = new ArrayList<>(); + + if (savedInstanceState == null) { + final OkHttpClient client = new OkHttpClient(); + final OkHttpClient.Builder retrofitClientBuilder = client.newBuilder(); + + if (BuildConfig.DEBUG) { + final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + retrofitClientBuilder.addInterceptor(interceptor); + retrofitClientBuilder.addNetworkInterceptor(interceptor); + } + + Retrofit retrofit = new Retrofit.Builder() + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .addConverterFactory(GsonConverterFactory.create()) + .baseUrl(YandexArtistApi.URL) + .client(retrofitClientBuilder.build()) + .build(); + + artistApi = retrofit.create(YandexArtistApi.class); + startDownload(); + } else { + genreList = savedInstanceState.getParcelableArrayList(TAG_SAVE_ARRAY); + if (genreList != null) adapter.addAllData(genreList); + } + + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + CriticalSectionsHandler criticalSectionsHandler = CriticalSectionsManager.getHandler(); + super.onScrollStateChanged(recyclerView, newState); + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + criticalSectionsHandler.stopSections(); + } else { + criticalSectionsHandler.startSection(1); + } + } + }); + + + } + + + private void startDownload() { +// first variants + /*Single.fromCallable(this::getResult) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(responseList -> { + Map genreMap = new HashMap<>(); + for (YandexArtistResponse yandexArtistResponse : responseList) { + for (String keyGenre : yandexArtistResponse.getGenres()) { + if (genreMap.get(keyGenre) == null) { + Genre genre = new Genre(); + genre.add(keyGenre, yandexArtistResponse.getName(), yandexArtistResponse.getCover().getSmall()); + genreMap.put(keyGenre, genre); + } else { + genreMap.get(keyGenre).add(keyGenre, yandexArtistResponse.getName(), yandexArtistResponse.getCover().getSmall()); + } + } + } + + for (String key : genreMap.keySet()) { + genreList.add(genreMap.get(key)); + } + Collections.sort(genreList); + adapter.addAllData(genreList); + }); +*/ + Single.fromCallable(this::getResult) + .subscribeOn(Schedulers.io()) + .flatMapObservable(Observable::from) + .reduce(new HashMap(), (genres, yandexArtistResponse) -> { + for (String genreStr : yandexArtistResponse.getGenres()) { + Genre genre = genres.get(genreStr); + if (genre == null) { + genres.put(genreStr, genre = new Genre(genreStr)); + } + genre.appendArtist(yandexArtistResponse); + } + return genres; + }) + .flatMap(genresMap -> Observable.from(genresMap.values())) + .toSortedList() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(genres -> { + adapter.addAllData(genres); + genreList.addAll(genres); + }); + } + + private List getResult() throws IOException { + Response> response; + response = artistApi.getListArtist() + .execute(); + return response.body(); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putParcelableArrayList(TAG_SAVE_ARRAY, (ArrayList) genreList); + } } diff --git a/app/src/main/res/drawable/placeholder.png b/app/src/main/res/drawable/placeholder.png new file mode 100644 index 0000000..541d531 Binary files /dev/null and b/app/src/main/res/drawable/placeholder.png differ diff --git a/app/src/main/res/drawable/red.png b/app/src/main/res/drawable/red.png new file mode 100644 index 0000000..5a3d15f Binary files /dev/null and b/app/src/main/res/drawable/red.png differ diff --git a/app/src/main/res/drawable/red_progress.xml b/app/src/main/res/drawable/red_progress.xml new file mode 100644 index 0000000..118e261 --- /dev/null +++ b/app/src/main/res/drawable/red_progress.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_content.xml b/app/src/main/res/layout/fragment_content.xml index 81016ea..60735b3 100644 --- a/app/src/main/res/layout/fragment_content.xml +++ b/app/src/main/res/layout/fragment_content.xml @@ -1,14 +1,5 @@ - - - - - \ No newline at end of file + diff --git a/app/src/main/res/layout/item_recycler_view.xml b/app/src/main/res/layout/item_recycler_view.xml new file mode 100644 index 0000000..2adec82 --- /dev/null +++ b/app/src/main/res/layout/item_recycler_view.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 02d4637..391094a 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -2,5 +2,10 @@ 16dp 16dp + 6dp + 50dp + 6dp + 10dp + 14dp diff --git a/dependencies.gradle b/dependencies.gradle index d9cb375..d340e7b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,7 +7,7 @@ ext.versions = [ compileSdk : 23, buildTools : '23.0.3', - androidGradlePlugin : '2.2.0-alpha4', + androidGradlePlugin : '2.2.0-alpha6', aptGradlePlugin : '1.8', retrolambdaGradlePlugin : '3.2.5', lombokGradlePlugin : '0.2.3.a2',