├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── Lobster-Regular.ttf
│ ├── java
│ └── com
│ │ └── saulmm
│ │ └── openlibra
│ │ ├── OnItemClickListener.java
│ │ ├── ScrollViewListener.java
│ │ ├── activities
│ │ ├── DetailActivity.java
│ │ └── MainActivity.java
│ │ ├── fragments
│ │ └── BooksFragment.java
│ │ ├── models
│ │ ├── Book.java
│ │ └── BookList.java
│ │ ├── network
│ │ └── Api.java
│ │ ├── other
│ │ ├── CustomAnimatorListener.java
│ │ └── CustomTransitionListener.java
│ │ └── views
│ │ ├── Utils.java
│ │ ├── adapters
│ │ └── BookAdapter.java
│ │ └── views
│ │ ├── LobstertextView.java
│ │ ├── ObservableScrollView.java
│ │ └── RecyclerInsetsDecoration.java
│ └── res
│ ├── anim
│ ├── alpha_off.xml
│ ├── alpha_on.xml
│ ├── fab_animation.xml
│ ├── translate_to_bottom.xml
│ ├── translate_up_off.xml
│ └── translate_up_on.xml
│ ├── drawable-hdpi
│ ├── ic_done_white_36dp.png
│ ├── ic_file_download_white_36dp.png
│ └── ic_launcher.png
│ ├── drawable-mdpi
│ ├── ic_done_white_36dp.png
│ ├── ic_file_download_white_36dp.png
│ └── ic_launcher.png
│ ├── drawable-xhdpi
│ ├── ic_done_white_36dp.png
│ ├── ic_file_download_white_36dp.png
│ └── ic_launcher.png
│ ├── drawable-xxhdpi
│ ├── ic_done_white_36dp.png
│ ├── ic_file_download_white_36dp.png
│ └── ic_launcher.png
│ ├── drawable
│ ├── card_background.xml
│ ├── gradient_black.xml
│ └── ripple_round.xml
│ ├── layout
│ ├── activity_detail.xml
│ ├── activity_main.xml
│ ├── fragment_books.xml
│ └── item_book.xml
│ ├── menu
│ └── menu_main.xml
│ ├── values-v21
│ └── styles.xml
│ ├── values-w820dp
│ └── dimens.xml
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── integers.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── gradle.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | #Android generated
2 | bin
3 | gen
4 | lint.xml
5 | lint
6 |
7 | #Eclipse
8 | .project
9 | .classpath
10 | .settings
11 | .checkstyle
12 |
13 | #IntelliJ IDEA
14 | .idea
15 | *.iml
16 | *.ipr
17 | *.iws
18 | classes
19 | gen-external-apklibs
20 |
21 | #gradle
22 | .gradle
23 | local.properties
24 | gradlew
25 | gradlew.bat
26 | gradle/
27 | build/
28 |
29 | #vi
30 | *.swp
31 |
32 | #other editors
33 | *.bak
34 |
35 | #Maven
36 | target
37 | release.properties
38 | pom.xml.*
39 |
40 | #Ant
41 | build.xml
42 | ant.properties
43 | local.properties
44 | proguard.cfg
45 | proguard-project.txt
46 |
47 | #Other
48 | .DS_Store
49 | Thumbs.db
50 | tmp
51 | *.tgz
52 | *.lock
53 | *.lck
54 | com_crashlytics_export_strings.xml
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenLibra-Material
2 |
3 | This repositores aims to show examples about material design in a real app, the application is a client of the webpage [OpenLibra](http://www.etnassoft.com/biblioteca/) a spanish web to download open source books.
4 |
5 | ## An example of how implement an adapter using Palette to tint each cell in a RecyclerView.
6 |
7 | This example is implemented with a `RecyclerView` a `GridLayoutManager` and an `Adapter` the adapter loads colors obtained from the `Palette` library of each cell to draw a `View` with the colors.
8 |
9 | 
10 |
11 | ## Building my own choreography with SharedElements
12 |
13 | Implemented a detail activity working with shared elements and animations, setting the order of each animation that composes the choreograpy, you can follow the material desing principle 'Motion provides meaning', _'All action takes place in a single environment. Objects are presented to the user without breaking the continuity of experience even as they transform and reorganize'_
14 |
15 | 
16 |
17 | ## Setting a RecyclerView insets and made translucent the Toolbar
18 |
19 | Set the RecyclerView insets, to show a little gap between columns and rows, and made the Toolbar translucent, as the last Field Trip app update, reaching a pretty effect.
20 |
21 | 
22 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.saulmm.openlibra"
9 | minSdkVersion 21
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | compile 'com.koushikdutta.ion:ion:2.0.0'
23 | compile 'com.android.support:support-v4:23.0.1'
24 | compile 'com.android.support:palette-v7:23.0.1'
25 | compile 'com.android.support:appcompat-v7:23.0.1'
26 | compile 'com.android.support:cardview-v7:23.0.1'
27 | compile 'com.android.support:recyclerview-v7:23.0.1'
28 | compile 'com.jakewharton:butterknife:6.0.0'
29 |
30 | compile fileTree(dir: 'libs', include: ['*.jar'])
31 | }
32 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/saulmm/android-sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/assets/Lobster-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/assets/Lobster-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/OnItemClickListener.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra;
2 |
3 | import android.view.View;
4 |
5 | public interface OnItemClickListener {
6 |
7 | void onClick(View v, int position);
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/ScrollViewListener.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra;
2 |
3 |
4 | import android.widget.ScrollView;
5 |
6 | public interface ScrollViewListener {
7 |
8 | void onScrollChanged(ScrollView scrollView, int x, int y, int oldx, int oldy);
9 |
10 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/activities/DetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.activities;
2 |
3 | import android.animation.Animator;
4 | import android.app.Activity;
5 | import android.graphics.Bitmap;
6 | import android.graphics.drawable.BitmapDrawable;
7 | import android.os.Bundle;
8 | import android.support.v7.graphics.Palette;
9 | import android.support.v7.widget.Toolbar;
10 | import android.transition.Transition;
11 | import android.view.View;
12 | import android.view.ViewPropertyAnimator;
13 | import android.view.animation.AnimationUtils;
14 | import android.widget.FrameLayout;
15 | import android.widget.ImageView;
16 | import android.widget.LinearLayout;
17 | import android.widget.TextView;
18 |
19 | import com.saulmm.openlibra.R;
20 | import com.saulmm.openlibra.fragments.BooksFragment;
21 | import com.saulmm.openlibra.models.Book;
22 | import com.saulmm.openlibra.other.CustomAnimatorListener;
23 | import com.saulmm.openlibra.other.CustomTransitionListener;
24 | import com.saulmm.openlibra.views.Utils;
25 |
26 | import butterknife.ButterKnife;
27 | import butterknife.InjectView;
28 |
29 |
30 | public class DetailActivity extends Activity {
31 |
32 | // UI Stuff
33 | @InjectView(R.id.card_view) FrameLayout contentCard;
34 | @InjectView(R.id.activity_detail_fab) View fabButton;
35 | @InjectView(R.id.activity_detail_main_container) View mainContaienr;
36 | @InjectView(R.id.activity_detail_titles_container) View titlesContainer;
37 | @InjectView(R.id.activity_detail_toolbar) Toolbar toolbar;
38 | @InjectView(R.id.activity_detail_book_info) LinearLayout bookInfoLayout;
39 | @InjectView(R.id.activity_detail_content) TextView contentTextView;
40 | @InjectView(R.id.activity_detail_rating_title) TextView ratingTextView;
41 | @InjectView(R.id.activity_detail_rating_value) TextView ratingValueTextView;
42 | @InjectView(R.id.activity_detail_summary_title) TextView summaryTitle;
43 | @InjectView(R.id.activity_detail_title) TextView titleTextView;
44 | @InjectView(R.id.activity_detail_subtitle) TextView subtitleTextView;
45 |
46 | private Book selectedBook;
47 |
48 | @Override
49 | protected void onCreate(Bundle savedInstanceState) {
50 |
51 | super.onCreate(savedInstanceState);
52 | setContentView(R.layout.activity_detail);
53 |
54 | ButterKnife.inject(this);
55 |
56 | // Recover items from the intent
57 | final int position = getIntent().getIntExtra("position", 0);
58 | selectedBook = (Book) getIntent().getSerializableExtra("selected_book");
59 |
60 | // Recover book cover from BooksFragment cache
61 | Bitmap bookCoverBitmap = BooksFragment.photoCache.get(position);
62 | ImageView toolbarBookCover = (ImageView) findViewById(R.id.activity_detail_cover);
63 | toolbarBookCover.setImageBitmap(bookCoverBitmap);
64 |
65 | // Fab button
66 | fabButton.setScaleX(0);
67 | fabButton.setScaleY(0);
68 |
69 | // Configure the views setting animation start point
70 | Utils.configureHideYView(contentCard);
71 | Utils.configureHideYView(bookInfoLayout);
72 | Utils.configureHideYView(mainContaienr);
73 |
74 | // Define toolbar as the shared element
75 | toolbar.setBackground(new BitmapDrawable(getResources(), bookCoverBitmap));
76 | toolbar.setTransitionName("cover" + position);
77 |
78 | // Add a listener to get noticed when the transition ends to animate the fab button
79 | getWindow().getSharedElementEnterTransition().addListener(sharedTransitionListener);
80 |
81 | // Generate palette colors
82 | Palette.generateAsync(bookCoverBitmap, paletteListener);
83 | }
84 |
85 |
86 | /**
87 | * I use a listener to get notified when the enter transition ends, and with that notifications
88 | * build my own coreography built with the elements of the UI
89 | *
90 | * Animations order:
91 | *
92 | * 1. The image is animated automatically by the SharedElementTransition
93 | * 2. The layout that contains the titles
94 | * 3. An alpha transition to show the text of the titles
95 | * 3. A scale animation to show the book info
96 | */
97 | private CustomTransitionListener sharedTransitionListener = new CustomTransitionListener() {
98 |
99 | @Override
100 | public void onTransitionEnd(Transition transition) {
101 |
102 | super.onTransitionEnd(transition);
103 |
104 | ViewPropertyAnimator showTitleAnimator = Utils.showViewByScale(mainContaienr);
105 | showTitleAnimator.setListener(new CustomAnimatorListener() {
106 |
107 | @Override
108 | public void onAnimationEnd(Animator animation) {
109 |
110 | super.onAnimationEnd(animation);
111 | titlesContainer.startAnimation(AnimationUtils.loadAnimation(DetailActivity.this, R.anim.alpha_on));
112 | titlesContainer.setVisibility(View.VISIBLE);
113 |
114 | Utils.showViewByScale(fabButton).start();
115 | Utils.showViewByScale(bookInfoLayout).start();
116 | }
117 | });
118 |
119 | showTitleAnimator.start();
120 | }
121 | };
122 |
123 | @Override
124 | public void onBackPressed() {
125 |
126 | ViewPropertyAnimator hideTitleAnimator = Utils.hideViewByScaleXY(fabButton);
127 |
128 | titlesContainer.startAnimation(AnimationUtils.loadAnimation(DetailActivity.this, R.anim.alpha_off));
129 | titlesContainer.setVisibility(View.INVISIBLE);
130 |
131 | Utils.hideViewByScaleY(bookInfoLayout);
132 |
133 | hideTitleAnimator.setListener(new CustomAnimatorListener() {
134 |
135 | @Override
136 | public void onAnimationEnd(Animator animation) {
137 |
138 | ViewPropertyAnimator hideFabAnimator = Utils.hideViewByScaleY(mainContaienr);
139 | hideFabAnimator.setListener(new CustomAnimatorListener() {
140 |
141 | @Override
142 | public void onAnimationEnd(Animator animation) {
143 |
144 | super.onAnimationEnd(animation);
145 | coolBack();
146 | }
147 | });
148 | }
149 | });
150 |
151 | hideTitleAnimator.start();
152 | }
153 |
154 | private Palette.PaletteAsyncListener paletteListener = new Palette.PaletteAsyncListener() {
155 |
156 | @Override
157 | public void onGenerated(Palette palette) {
158 |
159 | if (palette.getVibrantSwatch() != null) {
160 |
161 | Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
162 | mainContaienr.setBackgroundColor(vibrantSwatch.getRgb());
163 |
164 | getWindow().setStatusBarColor(vibrantSwatch.getRgb());
165 | getWindow().setNavigationBarColor(vibrantSwatch.getRgb());
166 |
167 | String content = selectedBook.getContent();
168 |
169 | if (content != null)
170 | contentTextView.setText(content);
171 |
172 | titleTextView.setText(selectedBook.getTitle());
173 | subtitleTextView.setTextColor(vibrantSwatch.getTitleTextColor());
174 | subtitleTextView.setText(selectedBook.getAuthor());
175 | ratingValueTextView.setText(selectedBook.getRating() + " / 10");
176 |
177 | summaryTitle.setTextColor(vibrantSwatch.getRgb());
178 | titleTextView.setTextColor(vibrantSwatch.getTitleTextColor());
179 | subtitleTextView.setTextColor(vibrantSwatch.getTitleTextColor());
180 | ratingTextView.setTextColor(vibrantSwatch.getTitleTextColor());
181 | ratingTextView.setTextColor(vibrantSwatch.getRgb());
182 | }
183 | }
184 | };
185 |
186 | private void coolBack() {
187 |
188 | try {
189 | super.onBackPressed();
190 |
191 | } catch (NullPointerException e) {
192 |
193 | // TODO: workaround
194 | }
195 |
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.activities;
2 |
3 | import android.os.Bundle;
4 | import android.os.Debug;
5 | import android.support.v7.app.ActionBarActivity;
6 | import android.support.v7.widget.Toolbar;
7 |
8 | import com.saulmm.openlibra.R;
9 | import com.saulmm.openlibra.fragments.BooksFragment;
10 |
11 |
12 | public class MainActivity extends ActionBarActivity {
13 |
14 | @Override
15 | protected void onCreate(Bundle savedInstanceState) {
16 | Debug.startMethodTracing("app");
17 | super.onCreate(savedInstanceState);
18 | setContentView(R.layout.activity_main);
19 |
20 | Toolbar toolbar = (Toolbar) findViewById(R.id.activity_main_toolbar);
21 | toolbar.setTitle("");
22 |
23 | BooksFragment booksFragment = (BooksFragment) getFragmentManager().findFragmentById(R.id.activity_main_last_books_fragment);
24 | booksFragment.setToolbar(toolbar);
25 |
26 | setSupportActionBar(toolbar);
27 |
28 | Debug.stopMethodTracing();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/fragments/BooksFragment.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.fragments;
2 |
3 |
4 | import android.app.ActivityOptions;
5 | import android.app.Fragment;
6 | import android.app.ProgressDialog;
7 | import android.content.Intent;
8 | import android.graphics.Bitmap;
9 | import android.os.Bundle;
10 | import android.support.v7.widget.GridLayoutManager;
11 | import android.support.v7.widget.RecyclerView;
12 | import android.support.v7.widget.Toolbar;
13 | import android.util.Log;
14 | import android.util.Pair;
15 | import android.util.SparseArray;
16 | import android.view.LayoutInflater;
17 | import android.view.MotionEvent;
18 | import android.view.View;
19 | import android.view.ViewGroup;
20 | import android.view.animation.AnimationUtils;
21 | import android.widget.ImageView;
22 |
23 | import com.google.gson.Gson;
24 | import com.google.gson.stream.JsonReader;
25 | import com.koushikdutta.async.future.FutureCallback;
26 | import com.koushikdutta.ion.Ion;
27 | import com.saulmm.openlibra.OnItemClickListener;
28 | import com.saulmm.openlibra.R;
29 | import com.saulmm.openlibra.activities.DetailActivity;
30 | import com.saulmm.openlibra.models.Book;
31 | import com.saulmm.openlibra.models.BookList;
32 | import com.saulmm.openlibra.network.Api;
33 | import com.saulmm.openlibra.views.adapters.BookAdapter;
34 | import com.saulmm.openlibra.views.views.RecyclerInsetsDecoration;
35 |
36 | import java.io.StringReader;
37 | import java.util.ArrayList;
38 |
39 | import static android.support.v7.widget.RecyclerView.OnScrollListener;
40 |
41 | public class BooksFragment extends Fragment {
42 |
43 | private static int COLUMNS = 2;
44 | public static SparseArray photoCache = new SparseArray(1);
45 |
46 | private ProgressDialog loadingDialog;
47 | private ArrayList books;
48 | private RecyclerView bookRecycler;
49 | private Toolbar toolbar;
50 | private int toolBarDefaultColor;
51 | private int toolBarSemiTransColor;
52 |
53 | public void setToolbar(Toolbar toolbar) {
54 |
55 | this.toolbar = toolbar;
56 | }
57 |
58 | @Override
59 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
60 |
61 | View rootView = inflater.inflate(R.layout.fragment_books, container, false);
62 |
63 | // Configure the recyclerview
64 | bookRecycler = (RecyclerView) rootView.findViewById(R.id.fragment_last_books_recycler);
65 | bookRecycler.setLayoutManager(new GridLayoutManager(getActivity(), COLUMNS));
66 | bookRecycler.addItemDecoration(new RecyclerInsetsDecoration(getActivity()));
67 | bookRecycler.setOnScrollListener(recyclerScrollListener);
68 | bookRecycler.setOnTouchListener(new View.OnTouchListener() {
69 | @Override
70 | public boolean onTouch(View v, MotionEvent event) {
71 | return false;
72 | }
73 | });
74 |
75 | // Init and show progress dialog
76 | loadingDialog = new ProgressDialog(getActivity());
77 | loadingDialog.setMessage(getResources().getString(R.string.loading_books));
78 | loadingDialog.show();
79 |
80 | toolBarDefaultColor = getResources().getColor(R.color.color_primary);
81 | toolBarSemiTransColor = getResources().getColor(R.color.color_primary_trans);
82 |
83 | // Load books from API
84 | Ion.with(getActivity())
85 | .load(Api.getLastBooks())
86 | .asString()
87 | .setCallback(booksCallback);
88 |
89 | return rootView;
90 | }
91 |
92 | // In future series this will be implemented with a view model presenter model
93 | private FutureCallback booksCallback = new FutureCallback() {
94 |
95 |
96 | @Override
97 | public void onCompleted(Exception e, String result) {
98 |
99 | if (e == null) {
100 |
101 | // Set the malformed JSON as lenient JsonReader
102 | result = Api.cleanJSON(result);
103 | JsonReader reader = new JsonReader(new StringReader(result));
104 | reader.setLenient(true);
105 |
106 | // Serialize reader into objects
107 | Gson gson = new Gson();
108 | BookList bookList = gson.fromJson(reader, BookList.class);
109 | books = bookList.getBooks();
110 |
111 | BookAdapter recyclerAdapter = new BookAdapter(books);
112 | recyclerAdapter.setOnItemClickListener(recyclerRowClickListener);
113 |
114 | // Update adapter
115 | bookRecycler.setAdapter(recyclerAdapter);
116 |
117 | // Dismiss loading dialog
118 | loadingDialog.dismiss();
119 |
120 |
121 | } else {
122 | Log.d("[DEBUG]", "BooksFragment onCompleted - ERROR: " + e.getMessage());
123 | }
124 | }
125 | };
126 |
127 | private OnItemClickListener recyclerRowClickListener = new OnItemClickListener() {
128 |
129 | @Override
130 | public void onClick(View v, int position) {
131 |
132 | Book selectedBook = books.get(position);
133 |
134 | Intent detailIntent = new Intent(getActivity(), DetailActivity.class);
135 | detailIntent.putExtra("position", position);
136 | detailIntent.putExtra("selected_book", selectedBook);
137 |
138 | ImageView coverImage = (ImageView) v.findViewById(R.id.item_book_img);
139 | ((ViewGroup) coverImage.getParent()).setTransitionGroup(false);
140 | photoCache.put(position, coverImage.getDrawingCache());
141 |
142 | // Setup the transition to the detail activity
143 | ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getActivity(),
144 | new Pair(coverImage, "cover" + position));
145 |
146 | startActivity(detailIntent, options.toBundle());
147 | }
148 | };
149 |
150 |
151 | private OnScrollListener recyclerScrollListener = new OnScrollListener() {
152 | public int lastDy;
153 | public boolean flag;
154 |
155 | @Override
156 | public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
157 |
158 | super.onScrolled(recyclerView, dx, dy);
159 |
160 | if (toolbar == null)
161 | throw new IllegalStateException("BooksFragment has not a reference of the main toolbar");
162 |
163 | // Is scrolling up
164 | if (dy > 10) {
165 |
166 | if (!flag) {
167 |
168 | showToolbar();
169 | flag = true;
170 | }
171 |
172 | // is scrolling down
173 | } else if (dy < -10) {
174 |
175 | if (flag) {
176 |
177 | hideToolbar();
178 | flag = false;
179 | }
180 | }
181 |
182 | lastDy = dy;
183 | }
184 | };
185 |
186 | private void showToolbar() {
187 |
188 | toolbar.startAnimation(AnimationUtils.loadAnimation(getActivity(),
189 | R.anim.translate_up_off));
190 | }
191 |
192 | private void hideToolbar() {
193 |
194 | toolbar.startAnimation(AnimationUtils.loadAnimation(getActivity(),
195 | R.anim.translate_up_on));
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/models/Book.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.models;
2 |
3 | import java.io.Serializable;
4 |
5 | public class Book implements Serializable {
6 |
7 | private String title;
8 | private String cover;
9 | private String author;
10 | private String content;
11 | private String publisher;
12 | private String publisher_date;
13 | private String pages;
14 | private String rating;
15 |
16 | public String getContent() {
17 |
18 | if (content != null) {
19 |
20 | content = replaceHtmlEntities(content);
21 | }
22 |
23 | return content;
24 | }
25 |
26 | public String replaceHtmlEntities (String content) {
27 |
28 | return content.replace("á","á")
29 | .replace("é","e")
30 | .replace("copy;","e")
31 | .replace("í","i")
32 | .replace(";shy","i")
33 | .replace("ó","ó")
34 | .replace("sup3;","ó")
35 | .replace("sup3;","ó")
36 | .replace("ñ","ñ")
37 | .replace("Ã&","")
38 | .replace("<ul>", "")
39 | .replace("</li>", "")
40 | .replace("</ul>", "")
41 | .replace("<li>", "\n\t\t");
42 |
43 | }
44 |
45 | public String getPublisher() {
46 | return publisher;
47 | }
48 |
49 | public String getPublisher_date() {
50 | return publisher_date;
51 | }
52 |
53 | public String getPages() {
54 | return pages;
55 | }
56 |
57 | public String getRating() {
58 | return rating;
59 | }
60 |
61 | public String getTitle() {
62 | return title;
63 | }
64 |
65 | public void setTitle(String title) {
66 | this.title = title;
67 | }
68 |
69 | public String getCover() {
70 | return cover;
71 | }
72 |
73 | public void setCover(String cover) {
74 | this.cover = cover;
75 | }
76 |
77 | public String getAuthor() {
78 | return author;
79 | }
80 |
81 | public void setAuthor(String author) {
82 | this.author = author;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/models/BookList.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.models;
2 |
3 | import java.util.ArrayList;
4 |
5 | public class BookList {
6 | private ArrayList books;
7 |
8 |
9 | public ArrayList getBooks() {
10 | return books;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/network/Api.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.network;
2 |
3 | import android.text.Html;
4 | import android.util.Log;
5 |
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * Created by saulmm on 15/11/14.
11 | */
12 | public class Api {
13 |
14 | private final static String ENDPOINT = "http://openlibra.com/api/v1/get/";
15 |
16 | public static String getMostVotedBooks (int n) {
17 |
18 | return String.format("%s%s%d", ENDPOINT, "?criteria=most_voted&num_items=", n);
19 | }
20 |
21 | public static String getLastBooks () {
22 |
23 | return "http://www.etnassoft.com/api/v1/get/?since=last_month&num_items=50&content";
24 | }
25 |
26 |
27 | public static String cleanJSON(String content) {
28 |
29 | // replace bad json params
30 | content = content.replaceFirst("\\(","{\"books\":");
31 | content = content.replace(")", "}");
32 |
33 | // // translate html entities
34 | // content = content
35 | // .replaceAll("á", "á")
36 | // .replaceAll("é", "é")
37 | // .replaceAll("Ã", "í")
38 | // .replaceAll("ó", "ó")
39 | // .replaceAll("ú", "ú")
40 | // .replaceAll("ñ", "ñ")
41 | // .replaceAll("Â", "");
42 | //
43 | // // Expression to extract href links
44 | // String hrefExpression = "";
45 | //
46 | // // replace entities and a tags
47 | // content = String.valueOf(Html.fromHtml(content));
48 | // content = extractGroups(content, hrefExpression);
49 |
50 | return content;
51 | }
52 |
53 |
54 | public static String extractGroups (String content, String regEx) {
55 | Pattern patron = Pattern.compile(regEx);
56 | Matcher matcher = patron.matcher(content);
57 |
58 | try {
59 | while (matcher.find())
60 | content= content.replaceFirst(matcher.group(0), matcher.group(1));
61 | } catch (IndexOutOfBoundsException e) {
62 | Log.e("[ERROR] saulmm.open_libra.other.Utils.extractGroups ", "Index of bounds");
63 | }
64 |
65 | return content;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/other/CustomAnimatorListener.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.other;
2 |
3 | import android.animation.Animator;
4 |
5 | public class CustomAnimatorListener implements Animator.AnimatorListener {
6 | @Override
7 | public void onAnimationStart(Animator animation) {
8 |
9 | }
10 |
11 | @Override
12 | public void onAnimationEnd(Animator animation) {
13 |
14 | }
15 |
16 | @Override
17 | public void onAnimationCancel(Animator animation) {
18 |
19 | }
20 |
21 | @Override
22 | public void onAnimationRepeat(Animator animation) {
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/other/CustomTransitionListener.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.other;
2 |
3 | import android.transition.Transition;
4 |
5 | /**
6 | * Created by saulmm on 17/11/14.
7 | */
8 | public class CustomTransitionListener implements Transition.TransitionListener {
9 |
10 | @Override
11 | public void onTransitionStart(Transition transition) {
12 |
13 | }
14 |
15 | @Override
16 | public void onTransitionEnd(Transition transition) {
17 |
18 | }
19 |
20 | @Override
21 | public void onTransitionCancel(Transition transition) {
22 |
23 | }
24 |
25 | @Override
26 | public void onTransitionPause(Transition transition) {
27 |
28 | }
29 |
30 | @Override
31 | public void onTransitionResume(Transition transition) {
32 |
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/views/Utils.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.views;
2 |
3 | import android.animation.ArgbEvaluator;
4 | import android.animation.ObjectAnimator;
5 | import android.view.View;
6 | import android.view.ViewPropertyAnimator;
7 | import android.view.animation.PathInterpolator;
8 |
9 | @SuppressWarnings("UnnecessaryLocalVariable")
10 | public class Utils {
11 |
12 | public final static int COLOR_ANIMATION_DURATION = 1000;
13 | public final static int DEFAULT_DELAY = 0;
14 |
15 | /**
16 | * Change the color of a view with an animation
17 | *
18 | * @param v the view to change the color
19 | * @param startColor the color to start animation
20 | * @param endColor the color to end the animation
21 | */
22 | public static void animateViewColor (View v, int startColor, int endColor) {
23 |
24 | ObjectAnimator animator = ObjectAnimator.ofObject(v, "backgroundColor",
25 | new ArgbEvaluator(), startColor, endColor);
26 |
27 | animator.setInterpolator(new PathInterpolator(0.4f,0f,1f,1f));
28 | animator.setDuration(COLOR_ANIMATION_DURATION);
29 | animator.start();
30 | }
31 |
32 | /**
33 | * Scale and set the pivot when the animation will start from
34 | *
35 | * @param v the view to set the pivot
36 | */
37 | public static void configureHideYView(View v) {
38 |
39 | v.setScaleY(0);
40 | v.setPivotY(0);
41 | }
42 |
43 | /**
44 | * Reduces the X & Y from a view
45 | *
46 | * @param v the view to be scaled
47 | *
48 | * @return the ViewPropertyAnimation to manage the animation
49 | */
50 | public static ViewPropertyAnimator hideViewByScaleXY(View v) {
51 |
52 | return hideViewByScale(v, DEFAULT_DELAY, 0, 0);
53 | }
54 |
55 | /**
56 | * Reduces the Y from a view
57 | *
58 | * @param v the view to be scaled
59 | *
60 | * @return the ViewPropertyAnimation to manage the animation
61 | */
62 | public static ViewPropertyAnimator hideViewByScaleY(View v) {
63 |
64 | return hideViewByScale(v, DEFAULT_DELAY, 1, 0);
65 | }
66 |
67 | /**
68 | * Reduces the X from a view
69 | *
70 | * @param v the view to be scaled
71 | *
72 | * @return the ViewPropertyAnimation to manage the animation
73 | */
74 | public static ViewPropertyAnimator hideViewByScalyInX(View v) {
75 |
76 | return hideViewByScale(v, DEFAULT_DELAY, 0, 1);
77 | }
78 |
79 | /**
80 | * Reduces the X & Y
81 | *
82 | * @param v the view to be scaled
83 | * @param delay to start the animation
84 | * @param x integer to scale
85 | * @param y integer to scale
86 | *
87 | * @return the ViewPropertyAnimation to manage the animation
88 | */
89 | private static ViewPropertyAnimator hideViewByScale (View v, int delay, int x, int y) {
90 |
91 | ViewPropertyAnimator propertyAnimator = v.animate().setStartDelay(delay)
92 | .scaleX(x).scaleY(y);
93 |
94 | return propertyAnimator;
95 | }
96 |
97 | /**
98 | * Shows a view by scaling
99 | *
100 | * @param v the view to be scaled
101 | *
102 | * @return the ViewPropertyAnimation to manage the animation
103 | */
104 | public static ViewPropertyAnimator showViewByScale (View v) {
105 |
106 | ViewPropertyAnimator propertyAnimator = v.animate().setStartDelay(DEFAULT_DELAY)
107 | .scaleX(1).scaleY(1);
108 |
109 | return propertyAnimator;
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/views/adapters/BookAdapter.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.views.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.support.v7.graphics.Palette;
6 | import android.support.v7.widget.RecyclerView;
7 | import android.util.Log;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.ImageView;
12 | import android.widget.LinearLayout;
13 | import android.widget.RelativeLayout;
14 | import android.widget.TextView;
15 |
16 | import com.koushikdutta.async.future.FutureCallback;
17 | import com.koushikdutta.ion.ImageViewBitmapInfo;
18 | import com.koushikdutta.ion.Ion;
19 | import com.saulmm.openlibra.OnItemClickListener;
20 | import com.saulmm.openlibra.R;
21 | import com.saulmm.openlibra.models.Book;
22 | import com.saulmm.openlibra.views.Utils;
23 |
24 | import java.util.ArrayList;
25 |
26 | /**
27 | * Created by saulmm on 08/12/14.
28 | */
29 | public class BookAdapter extends RecyclerView.Adapter {
30 |
31 | private final ArrayList books;
32 | private Context context;
33 | private int defaultBackgroundcolor;
34 | private OnItemClickListener onItemClickListener;
35 | private int lastPosition = -1;
36 | private static final int SCALE_DELAY = 30;
37 |
38 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
39 | this.onItemClickListener = onItemClickListener;
40 | }
41 |
42 | public BookAdapter(ArrayList books) {
43 |
44 | this.books = books;
45 | }
46 |
47 | @Override
48 | public BooksViewHolder onCreateViewHolder(ViewGroup viewGroup, int position) {
49 |
50 | View rowView = LayoutInflater.from(viewGroup.getContext())
51 | .inflate(R.layout.item_book, viewGroup, false);
52 |
53 | this.context = viewGroup.getContext();
54 | defaultBackgroundcolor = context.getResources().getColor(R.color.book_without_palette);
55 |
56 | return new BooksViewHolder(rowView, onItemClickListener);
57 | }
58 |
59 | @Override
60 | public void onBindViewHolder(final BooksViewHolder booksViewHolder, final int position) {
61 |
62 | final Book currentBook = books.get(position);
63 | booksViewHolder.bookTitle.setText(currentBook.getTitle());
64 | booksViewHolder.bookAuthor.setText(currentBook.getAuthor());
65 | booksViewHolder.bookCover.setDrawingCacheEnabled(true);
66 |
67 | Ion.with(context)
68 | .load(books.get(position).getCover())
69 | .intoImageView(booksViewHolder.bookCover)
70 | .withBitmapInfo()
71 | .setCallback(new FutureCallback() {
72 | @Override
73 | public void onCompleted(Exception e, ImageViewBitmapInfo result) {
74 |
75 | if (e == null && result != null) {
76 |
77 | setCellColors(result.getBitmapInfo().bitmap, booksViewHolder, position);
78 | amimateCell(booksViewHolder);
79 | }
80 | }
81 | });
82 | }
83 | private static final int MAX_PHOTO_ANIMATION_DELAY = 100;
84 | private long profileHeaderAnimationStartTime = 0;
85 |
86 | private void amimateCell(BooksViewHolder booksViewHolder) {
87 |
88 | int cellPosition = booksViewHolder.getPosition();
89 |
90 | if (!booksViewHolder.animated) {
91 |
92 | booksViewHolder.animated = true;
93 | booksViewHolder.bookContainer.setScaleY(0);
94 | booksViewHolder.bookContainer.setScaleX(0);
95 | booksViewHolder.bookContainer.animate()
96 | .scaleY(1).scaleX(1)
97 | .setDuration(200)
98 | .setStartDelay(SCALE_DELAY * cellPosition)
99 | .start();
100 | }
101 |
102 | }
103 |
104 |
105 | public void setCellColors (Bitmap b, final BooksViewHolder viewHolder, final int position) {
106 |
107 | if (b != null) {
108 | Palette.generateAsync(b, new Palette.PaletteAsyncListener() {
109 |
110 | @Override
111 | public void onGenerated(Palette palette) {
112 |
113 | Palette.Swatch vibrantSwatch = palette.getVibrantSwatch();
114 |
115 | if (vibrantSwatch != null) {
116 |
117 | viewHolder.bookTitle.setTextColor(vibrantSwatch.getTitleTextColor());
118 | viewHolder.bookAuthor.setTextColor(vibrantSwatch.getTitleTextColor());
119 | viewHolder.bookCover.setTransitionName("cover" + position);
120 | viewHolder.bookTextcontainer.setOnClickListener(new View.OnClickListener() {
121 | @Override
122 | public void onClick(View v) {
123 | onItemClickListener.onClick(v, position);
124 | }
125 | });
126 |
127 | Utils.animateViewColor(viewHolder.bookTextcontainer, defaultBackgroundcolor,
128 | vibrantSwatch.getRgb());
129 |
130 | } else {
131 |
132 | Log.e("[ERROR]", "BookAdapter onGenerated - The VibrantSwatch were null at: " + position);
133 | }
134 | }
135 | });
136 | }
137 | }
138 |
139 | @Override
140 | public int getItemCount() {
141 |
142 | return books.size();
143 | }
144 | }
145 |
146 | class BooksViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
147 |
148 | protected LinearLayout bookContainer;
149 | protected RelativeLayout bookTextcontainer;
150 | protected ImageView bookCover;
151 | protected TextView bookTitle;
152 | protected TextView bookAuthor;
153 | private OnItemClickListener onItemClickListener;
154 | protected boolean animated = false;
155 |
156 | public BooksViewHolder(View itemView, OnItemClickListener onItemClickListener) {
157 |
158 | super(itemView);
159 | this.onItemClickListener = onItemClickListener;
160 |
161 | bookContainer = (LinearLayout) itemView.findViewById(R.id.item_book_container);
162 | bookTextcontainer = (RelativeLayout) itemView.findViewById(R.id.item_book_text_container);
163 | bookCover = (ImageView) itemView.findViewById(R.id.item_book_img);
164 | bookTitle = (TextView) itemView.findViewById(R.id.item_book_title);
165 | bookAuthor = (TextView) itemView.findViewById(R.id.item_book_author);
166 | bookCover.setOnClickListener(this);
167 |
168 | }
169 |
170 | @Override
171 | public void onClick(View v) {
172 |
173 | onItemClickListener.onClick(v, getPosition());
174 |
175 | }
176 | }
177 |
178 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/views/views/LobstertextView.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.views.views;
2 |
3 | import android.content.Context;
4 | import android.graphics.Typeface;
5 | import android.util.AttributeSet;
6 | import android.widget.TextView;
7 |
8 | public class LobsterTextView extends TextView {
9 | public LobsterTextView(Context context) {
10 | super(context);
11 | init(context);
12 | }
13 |
14 | public LobsterTextView(Context context, AttributeSet attrs) {
15 | super(context, attrs);
16 | init(context);
17 | }
18 |
19 | public LobsterTextView(Context context, AttributeSet attrs, int defStyleAttr) {
20 | super(context, attrs, defStyleAttr);
21 | init(context);
22 | }
23 |
24 | private void init(Context context) {
25 | Typeface t = Typeface.createFromAsset(context.getAssets(), "Lobster-Regular.ttf");
26 | this.setTypeface(t);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/views/views/ObservableScrollView.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.views.views;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ScrollView;
6 |
7 | import com.saulmm.openlibra.ScrollViewListener;
8 |
9 |
10 | public class ObservableScrollView extends ScrollView {
11 |
12 | private ScrollViewListener scrollViewListener = null;
13 |
14 | public ObservableScrollView(Context context) {
15 | super(context);
16 | }
17 |
18 | public ObservableScrollView(Context context, AttributeSet attrs, int defStyle) {
19 | super(context, attrs, defStyle);
20 | }
21 |
22 | public ObservableScrollView(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | }
25 |
26 | public void setScrollViewListener(ScrollViewListener scrollViewListener) {
27 | this.scrollViewListener = scrollViewListener;
28 | }
29 |
30 | @Override
31 | protected void onScrollChanged(int x, int y, int oldx, int oldy) {
32 | super.onScrollChanged(x, y, oldx, oldy);
33 | if(scrollViewListener != null) {
34 | scrollViewListener.onScrollChanged(this, x, y, oldx, oldy);
35 | }
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/saulmm/openlibra/views/views/RecyclerInsetsDecoration.java:
--------------------------------------------------------------------------------
1 | package com.saulmm.openlibra.views.views;
2 |
3 | import android.content.Context;
4 | import android.graphics.Rect;
5 | import android.support.v7.widget.RecyclerView;
6 | import android.view.View;
7 |
8 | import com.saulmm.openlibra.R;
9 |
10 |
11 | /**
12 | * ItemDecoration implementation that applies an inset margin
13 | * around each child of the RecyclerView. The inset value is controlled
14 | * by a dimension resource.
15 | *
16 | * by Dave Smith at: https://github.com/devunwired/recyclerview-playground
17 | */
18 | public class RecyclerInsetsDecoration extends RecyclerView.ItemDecoration {
19 |
20 | private int mInsets;
21 |
22 | public RecyclerInsetsDecoration(Context context) {
23 | mInsets = context.getResources().getDimensionPixelSize(R.dimen.insets);
24 | }
25 |
26 | @Override
27 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
28 |
29 | //We can supply forced insets for each item view here in the Rect
30 | super.getItemOffsets(outRect, view, parent, state);
31 | outRect.set(mInsets, mInsets, mInsets, mInsets);
32 | }
33 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/alpha_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/alpha_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fab_animation.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
11 |
13 |
14 |
15 | -
18 |
19 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/translate_to_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/translate_up_off.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/translate_up_on.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_done_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-hdpi/ic_done_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_file_download_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-hdpi/ic_file_download_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_done_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-mdpi/ic_done_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_file_download_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-mdpi/ic_file_download_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_done_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xhdpi/ic_done_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_file_download_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xhdpi/ic_file_download_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_done_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xxhdpi/ic_done_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_file_download_white_36dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xxhdpi/ic_file_download_white_36dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/saulmm/OpenLibra-Material/285fcca8fe50a0deb6f3034c5f4918537a4edb5c/app/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/card_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | -
13 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/gradient_black.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ripple_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 | -
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
16 |
17 |
23 |
24 |
30 |
31 |
39 |
40 |
49 |
50 |
60 |
61 |
73 |
74 |
75 |
76 |
77 |
78 |
92 |
93 |
104 |
105 |
106 |
107 |
117 |
118 |
125 |
126 |
135 |
136 |
143 |
144 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
18 |
19 |
26 |
27 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_books.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_book.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
22 |
23 |
30 |
31 |
42 |
43 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #1C1D23
5 | #ffeae1da
6 |
7 |
8 | #F50057
9 | #33f50057
10 | #AE0554
11 | #6734BA
12 | #ff232323
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 200dp
6 | 55dp
7 | 1dp
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/integers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 300
4 | 300
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | OpenLibra
5 | Settings
6 |
7 |
8 | Loading books\nplease wait
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc mollis nunc massa, quis suscipit orci mattis a. Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum. Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum. Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Ut vestibulum, Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Morbi ac dui in lacus finibus hendrerit. Ut vestibulum, Nulla rutrum fringilla finibus. Morbi ac dui in lacus finibus hendrerit. Ut vestibulum
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:1.3.0'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------