diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f9edd0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# built application files +*.apk +*.ap_ +.gradle/ +build/ + +# files for the dex VM +*.dex + +# Java class files +*.class + +# generated files +bin/ +gen/ +out/ +target/ + +# Local configuration file (sdk path, etc) +local.properties + +# Eclipse project files +.classpath +.project + +# Idea IDE files +*.idea/ +*.iml + +*.DS_STORE + +custom_env.gradle diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..70224f9 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,3 @@ +/build +/src/androidTest +/src/test \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..fde28da --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,59 @@ +apply plugin: 'com.android.application' +apply plugin: 'com.neenbedankt.android-apt' + +android { + compileSdkVersion 24 + buildToolsVersion "23.0.3" + + defaultConfig { + applicationId "com.bobrusha.android.artists" + minSdkVersion 14 + targetSdkVersion 24 + versionCode 1 + versionName "1.0" + } + signingConfigs { + release { + storeFile file('/Users/aleksandra/AndroidStudioProjects/Artists/app/my-release-key.keystore') + storePassword "qwerty" + keyAlias "mobilization" + keyPassword "qwerty" + } + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.release + } + } +} + +repositories { + mavenCentral() + jcenter() + maven { url "https://clojars.org/repo/" } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + testCompile 'junit:junit:4.12' + compile 'com.android.support:appcompat-v7:24.1.1' + compile 'com.android.support:recyclerview-v7:24.1.1' + compile 'com.android.support:design:24.1.1' + compile 'com.android.support:support-v4:24.1.1' + compile 'com.android.support:preference-v7:24.1.1' + compile 'com.android.support:preference-v14:24.1.1' + compile 'com.squareup.okhttp3:okhttp:3.2.0' + compile 'com.squareup.picasso:picasso:2.5.2' + + compile 'com.jakewharton:butterknife:8.2.1' + apt 'com.jakewharton:butterknife-compiler:8.2.1' + + provided 'frankiesardo:auto-parcel:1.0.1' + apt 'frankiesardo:auto-parcel:1.0.3' + + compile 'com.fasterxml.jackson.core:jackson-core:2.8.1' + compile 'com.fasterxml.jackson.core:jackson-annotations:2.8.1' + compile 'com.fasterxml.jackson.core:jackson-databind:2.8.1' +} diff --git a/app/my-release-key.keystore b/app/my-release-key.keystore new file mode 100644 index 0000000..b3acb5a Binary files /dev/null and b/app/my-release-key.keystore differ diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..fa1fc1d --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/aleksandra/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5efae56..800439d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ @@ -22,13 +23,6 @@ - - - diff --git a/app/src/main/java/com/bobrusha/android/artists/ArtistDetailActivity.java b/app/src/main/java/com/bobrusha/android/artists/ArtistDetailActivity.java deleted file mode 100644 index df34236..0000000 --- a/app/src/main/java/com/bobrusha/android/artists/ArtistDetailActivity.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.bobrusha.android.artists; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.view.MenuItem; -import android.view.View; -import android.widget.ImageView; -import android.widget.TextView; - -import com.bobrusha.android.artists.model.ArtistInfo; -import com.squareup.picasso.Callback; -import com.squareup.picasso.Picasso; - -/** - * Activity with detailed information about chosen musician. - * - * @author Aleksandra Bobrova - */ -public class ArtistDetailActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.activity_artist_detail); - Intent intent = getIntent(); - ArtistInfo artistInfo = intent.getParcelableExtra(Constants.EXTRA_ARTIST); - ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(artistInfo.getName()); - actionBar.setDisplayHomeAsUpEnabled(true); - } - - final ImageView imageView = (ImageView) findViewById(R.id.artist_detail_big_img); - Picasso.with(imageView.getContext()) - .load(artistInfo.getCover().getBig()) - .into(imageView, new Callback() { - @Override - public void onSuccess() { - imageView.setVisibility(View.VISIBLE); - } - - @Override - public void onError() { - //Stop progressBar and show text - findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE); - findViewById(R.id.artist_detail_no_image).setVisibility(View.VISIBLE); - - } - }); - - TextView genreTextView = (TextView) findViewById(R.id.artist_detail_genre_text); - genreTextView.setText(TextUtils.join(", ", artistInfo.getGenres())); - - TextView albumsAndTracksTextView = (TextView) findViewById(R.id.artist_detail_albums_and_tracks); - String pattern = getString(R.string.artist_detail_albums_and_tracks); - albumsAndTracksTextView.setText( - String.format(pattern, artistInfo.getAlbums(), artistInfo.getTracks()) - ); - - TextView textOfBiographyTextView = (TextView) findViewById(R.id.artist_detail_biography_text); - textOfBiographyTextView.setText(artistInfo.getDescription()); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - } - return super.onOptionsItemSelected(item); - } -} diff --git a/app/src/main/java/com/bobrusha/android/artists/ArtistInfoLoader.java b/app/src/main/java/com/bobrusha/android/artists/ArtistInfoLoader.java index 5e7deed..6bc0e8c 100644 --- a/app/src/main/java/com/bobrusha/android/artists/ArtistInfoLoader.java +++ b/app/src/main/java/com/bobrusha/android/artists/ArtistInfoLoader.java @@ -1,11 +1,13 @@ package com.bobrusha.android.artists; import android.content.Context; +import android.database.sqlite.SQLiteDatabase; import android.support.v4.content.AsyncTaskLoader; +import com.bobrusha.android.artists.db.DBManager; import com.bobrusha.android.artists.model.ArtistInfo; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.List; @@ -21,12 +23,8 @@ * @author Aleksandra Bobrova */ public class ArtistInfoLoader extends AsyncTaskLoader> { - private static final String URL = "http://cache-default04f.cdn.yandex.net/download.cdn.yandex.net/mobilization-2016/artists.json"; + private static final String URL = "http://download.cdn.yandex.net/mobilization-2016/artists.json"; private OkHttpClient client = new OkHttpClient(); - private Gson mGson = new Gson(); - - private TypeToken> artists = new TypeToken>() { - }; public ArtistInfoLoader(Context context) { super(context); @@ -54,8 +52,15 @@ public List loadInBackground() { try { response = client.newCall(request).execute(); ResponseBody responseBody = response.body(); - List artistInfoList = mGson.fromJson(responseBody.charStream(), artists.getType()); + + ObjectMapper objectMapper = new ObjectMapper(); + List artistInfoList = objectMapper.readValue(responseBody.charStream(), new TypeReference>() { + }); + responseBody.close(); + + SQLiteDatabase db = MyApplication.getDbHelper().getWritableDatabase(); + DBManager.putArtists(db, artistInfoList); return artistInfoList; } catch (IOException e) { e.printStackTrace(); diff --git a/app/src/main/java/com/bobrusha/android/artists/BusProvider.java b/app/src/main/java/com/bobrusha/android/artists/BusProvider.java deleted file mode 100644 index acf881a..0000000 --- a/app/src/main/java/com/bobrusha/android/artists/BusProvider.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.bobrusha.android.artists; - -import com.squareup.otto.Bus; - -/** - * Class for providing instance of Bus. - * - * @author Aleksandra Bobrova - * @see Bus - */ -public class BusProvider { - private static final Bus mInstance = new Bus(); - - private BusProvider() { - } - - public static Bus getInstance() { - return mInstance; - } -} diff --git a/app/src/main/java/com/bobrusha/android/artists/CacheLoader.java b/app/src/main/java/com/bobrusha/android/artists/CacheLoader.java new file mode 100644 index 0000000..60a95d2 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/CacheLoader.java @@ -0,0 +1,45 @@ +package com.bobrusha.android.artists; + +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.support.v4.content.AsyncTaskLoader; +import android.util.Log; + +import com.bobrusha.android.artists.db.Contract; +import com.bobrusha.android.artists.db.DBManager; +import com.bobrusha.android.artists.model.ArtistInfo; +import com.bobrusha.android.artists.model.Cover; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Created by Aleksandra on 20/07/16. + */ +public class CacheLoader extends AsyncTaskLoader> { + + public CacheLoader(Context context) { + super(context); + } + + @Override + protected void onStartLoading() { + super.onStartLoading(); + forceLoad(); + } + + @Override + public List loadInBackground() { + SQLiteDatabase db = MyApplication.getDbHelper().getReadableDatabase(); + Cursor c = db.query(Contract.ArtistEntry.TABLE_NAME, null, null, null, null, null, null, null); + List artists = new ArrayList<>(); + for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { + artists.add(DBManager.getArtistFromCursor(c)); + } + c.close(); + return artists; + } + +} diff --git a/app/src/main/java/com/bobrusha/android/artists/Constants.java b/app/src/main/java/com/bobrusha/android/artists/Constants.java index 0d17407..1c8363b 100644 --- a/app/src/main/java/com/bobrusha/android/artists/Constants.java +++ b/app/src/main/java/com/bobrusha/android/artists/Constants.java @@ -1,7 +1,6 @@ package com.bobrusha.android.artists; /** - * * @author Aleksandra Bobrova */ @@ -10,6 +9,7 @@ public interface Constants { String PACKAGE_NAME_PREFIX = "com.bobrusha.android.artists."; String EXTRA_ARTIST = PACKAGE_NAME_PREFIX + "artist"; - int ARTIST_INFO_LOADER_ID = 1; + int ARTIST_INFO_LOADER_ID = 10; + int CACHE_LOADER_ID = 20; } diff --git a/app/src/main/java/com/bobrusha/android/artists/MainActivity.java b/app/src/main/java/com/bobrusha/android/artists/MainActivity.java deleted file mode 100644 index c498549..0000000 --- a/app/src/main/java/com/bobrusha/android/artists/MainActivity.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.bobrusha.android.artists; - -import android.content.Intent; -import android.os.Bundle; -import android.support.design.widget.Snackbar; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; - -import com.bobrusha.android.artists.recycler_view.ArtistPreviewAdapter; -import com.bobrusha.android.artists.recycler_view.DividerItemDecoration; -import com.bobrusha.android.artists.event.ArtistPreviewOnClickEvent; -import com.bobrusha.android.artists.model.ArtistInfo; -import com.squareup.otto.Subscribe; - -import java.util.List; - -/** - * Main Activity for showing list of musicians. - * - * @author Aleksandra Bobrova - */ -public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks> { - - private RecyclerView.Adapter mAdapter; - private SwipeRefreshLayout mSwipeRefreshLayout; - private Snackbar mSnackbar; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view_artists); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - - mAdapter = new ArtistPreviewAdapter(); - recyclerView.setAdapter(mAdapter); - - recyclerView.addItemDecoration(new DividerItemDecoration(this, R.drawable.divider)); - - mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.refresh_layout); - mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - getSupportLoaderManager().restartLoader(Constants.ARTIST_INFO_LOADER_ID, null, MainActivity.this); - mSwipeRefreshLayout.setRefreshing(false); - } - }); - - getSupportLoaderManager().initLoader(Constants.ARTIST_INFO_LOADER_ID, null, this); - } - - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new ArtistInfoLoader(this); - } - - @Override - public void onLoadFinished(Loader> loader, List data) { - ((ArtistPreviewAdapter) mAdapter).setDataset(data); - mSwipeRefreshLayout.setRefreshing(false); - - // Show snackBar if no data was loaded - if (data == null) { - if (mSnackbar == null) { - mSnackbar = Snackbar.make(findViewById(R.id.refresh_layout), - R.string.no_data_to_display, - Snackbar.LENGTH_INDEFINITE); - } - mSnackbar.show(); - } else { - if (mSnackbar != null) { - mSnackbar.dismiss(); - } - } - } - - @Override - public void onLoaderReset(Loader> loader) { - - } - - @Override - protected void onResume() { - super.onResume(); - BusProvider.getInstance().register(this); - } - - @Override - protected void onPause() { - super.onPause(); - BusProvider.getInstance().unregister(this); - } - - /** - * Method that calling then user chose musician. - * - * @param event – event for method invocation using Bus. - */ - @Subscribe - public void onArtistSelected(ArtistPreviewOnClickEvent event) { - Intent intent = new Intent(this, ArtistDetailActivity.class); - ArtistInfo artistInfo = event.getArtistInfo(); - intent.putExtra(Constants.EXTRA_ARTIST, artistInfo); - startActivity(intent); - } -} diff --git a/app/src/main/java/com/bobrusha/android/artists/MyApplication.java b/app/src/main/java/com/bobrusha/android/artists/MyApplication.java new file mode 100644 index 0000000..1d2d3b5 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/MyApplication.java @@ -0,0 +1,23 @@ +package com.bobrusha.android.artists; + +import android.app.Application; + +import com.bobrusha.android.artists.db.MyDbHelper; + +/** + * Created by Aleksandra on 20/07/16. + */ +public class MyApplication extends Application { + private static MyDbHelper dbHelper; + + @Override + public void onCreate() { + super.onCreate(); + + dbHelper = new MyDbHelper(this); + } + + public static MyDbHelper getDbHelper() { + return dbHelper; + } +} diff --git a/app/src/main/java/com/bobrusha/android/artists/db/Contract.java b/app/src/main/java/com/bobrusha/android/artists/db/Contract.java new file mode 100644 index 0000000..95c42d4 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/db/Contract.java @@ -0,0 +1,22 @@ +package com.bobrusha.android.artists.db; + +import android.provider.BaseColumns; + +/** + * Created by Aleksandra on 20/07/16. + */ +public final class Contract { + + public static abstract class ArtistEntry implements BaseColumns { + public static final String TABLE_NAME = "artist"; + public static final String COLUMN_NAME_ARTIST_ID = "artist_id"; + public static final String COLUMN_NAME_ARTIST_NAME = "artist_name"; + public static final String COLUMN_NAME_GENRES = "genres"; + public static final String COLUMN_NAME_TRACKS = "amount_of_tracks"; + public static final String COLUMN_NAME_ALBUMS = "amount_of_albums"; + public static final String COLUMN_NAME_LINK = "link"; + public static final String COLUMN_NAME_DESCRIPTION = "description"; + public static final String COLUMN_NAME_COVER_SMALL = "cover_small"; + public static final String COLUMN_NAME_COVER_BIG = "cover_big"; + } +} diff --git a/app/src/main/java/com/bobrusha/android/artists/db/DBManager.java b/app/src/main/java/com/bobrusha/android/artists/db/DBManager.java new file mode 100644 index 0000000..99a4137 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/db/DBManager.java @@ -0,0 +1,77 @@ +package com.bobrusha.android.artists.db; + +import android.content.ContentValues; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.text.TextUtils; + +import com.bobrusha.android.artists.model.ArtistInfo; +import com.bobrusha.android.artists.model.Cover; + +import java.util.Arrays; +import java.util.List; + +/** + * Created by Aleksandra on 20/07/16. + */ +public class DBManager { + + + public static void putArtist(SQLiteDatabase db, ArtistInfo artist) { + ContentValues values = new ContentValues(); + values.put(Contract.ArtistEntry.COLUMN_NAME_ARTIST_ID, artist.id()); + values.put(Contract.ArtistEntry.COLUMN_NAME_ARTIST_NAME, artist.name()); + values.put(Contract.ArtistEntry.COLUMN_NAME_GENRES, TextUtils.join(", ", artist.genres())); + values.put(Contract.ArtistEntry.COLUMN_NAME_TRACKS, artist.tracks()); + values.put(Contract.ArtistEntry.COLUMN_NAME_ALBUMS, artist.albums()); + values.put(Contract.ArtistEntry.COLUMN_NAME_LINK, artist.link()); + values.put(Contract.ArtistEntry.COLUMN_NAME_DESCRIPTION, artist.description()); + values.put(Contract.ArtistEntry.COLUMN_NAME_COVER_BIG, artist.cover().getBig()); + values.put(Contract.ArtistEntry.COLUMN_NAME_COVER_SMALL, artist.cover().getSmall()); + + String selection = Contract.ArtistEntry.COLUMN_NAME_ARTIST_ID + " LIKE ?"; + String[] selectionArgs = {String.valueOf(artist.id())}; + + int count = db.update( + Contract.ArtistEntry.TABLE_NAME, + values, + selection, + selectionArgs); + + if (count == 0) { + db.insert(Contract.ArtistEntry.TABLE_NAME, null, values); + } + } + + + public static void putArtists(SQLiteDatabase db, List artists) { + for (ArtistInfo artist : artists) { + putArtist(db, artist); + } + + Cursor c = db.query(Contract.ArtistEntry.TABLE_NAME, null, null, null, null, null, null); + } + + + public static ArtistInfo getArtistFromCursor(Cursor c) { + String[] genres = c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_GENRES)).split(", ", -1); + + Cover cover = new Cover(); + cover.setSmall(c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_COVER_SMALL))); + cover.setBig(c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_COVER_BIG))); + + ArtistInfo artistInfo = ArtistInfo.builder() + .id(c.getLong(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_ARTIST_ID))) + .name(c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_ARTIST_NAME))) + .genres(Arrays.asList(genres)) + .tracks(c.getLong(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_TRACKS))) + .albums(c.getLong(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_ALBUMS))) + .link(c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_LINK))) + .description(c.getString(c.getColumnIndex(Contract.ArtistEntry.COLUMN_NAME_DESCRIPTION))) + .cover(cover) + .build(); + + return artistInfo; + } + +} diff --git a/app/src/main/java/com/bobrusha/android/artists/db/MyDbHelper.java b/app/src/main/java/com/bobrusha/android/artists/db/MyDbHelper.java new file mode 100644 index 0000000..458cbc2 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/db/MyDbHelper.java @@ -0,0 +1,51 @@ +package com.bobrusha.android.artists.db; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +/** + * Created by Aleksandra on 20/07/16. + */ +public class MyDbHelper extends SQLiteOpenHelper { + public static final int DATABASE_VERSION = 1; + public static final String DATABASE_NAME = "Artists.db"; + + private static final String TEXT_TYPE = " TEXT"; + private static final String INTEGER_TYPE = " INTEGER"; + private static final String SEP = ", "; + private static final String CREATE_DB = "CREATE TABLE " + Contract.ArtistEntry.TABLE_NAME + + " (" + Contract.ArtistEntry._ID + " INTEGER PRIMARY KEY " + SEP + + Contract.ArtistEntry.COLUMN_NAME_ARTIST_ID + INTEGER_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_ARTIST_NAME + TEXT_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_GENRES + TEXT_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_TRACKS + INTEGER_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_ALBUMS + INTEGER_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_LINK + TEXT_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_DESCRIPTION + TEXT_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_COVER_BIG + TEXT_TYPE + SEP + + Contract.ArtistEntry.COLUMN_NAME_COVER_SMALL + TEXT_TYPE + + " )"; + + private static final String SQL_DELETE_ENTRIES = + "DROP TABLE IF EXISTS " + Contract.ArtistEntry.TABLE_NAME; + + + public MyDbHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + + } + + @Override + public void onCreate(SQLiteDatabase sqLiteDatabase) { + sqLiteDatabase.execSQL(CREATE_DB); + } + + @Override + public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) { + sqLiteDatabase.execSQL(SQL_DELETE_ENTRIES); + onCreate(sqLiteDatabase); + } + + +} diff --git a/app/src/main/java/com/bobrusha/android/artists/event/ArtistPreviewOnClickEvent.java b/app/src/main/java/com/bobrusha/android/artists/event/ArtistPreviewOnClickEvent.java index 1e337ef..378ea45 100644 --- a/app/src/main/java/com/bobrusha/android/artists/event/ArtistPreviewOnClickEvent.java +++ b/app/src/main/java/com/bobrusha/android/artists/event/ArtistPreviewOnClickEvent.java @@ -9,13 +9,13 @@ * @see com.squareup.otto.Bus */ public class ArtistPreviewOnClickEvent { - private final ArtistInfo mArtistInfo; + private final ArtistInfo artistInfo; public ArtistPreviewOnClickEvent(ArtistInfo artistInfo) { - mArtistInfo = artistInfo; + this.artistInfo = artistInfo; } public ArtistInfo getArtistInfo() { - return mArtistInfo; + return artistInfo; } } diff --git a/app/src/main/java/com/bobrusha/android/artists/model/ArtistInfo.java b/app/src/main/java/com/bobrusha/android/artists/model/ArtistInfo.java index 4e8f7ed..eb1a8da 100644 --- a/app/src/main/java/com/bobrusha/android/artists/model/ArtistInfo.java +++ b/app/src/main/java/com/bobrusha/android/artists/model/ArtistInfo.java @@ -1,7 +1,13 @@ package com.bobrusha.android.artists.model; -import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.google.auto.value.AutoValue; import java.util.List; @@ -10,113 +16,89 @@ * * @author Aleksandra Bobrova */ -public class ArtistInfo implements Parcelable { - 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() { - } +@AutoValue +@JsonDeserialize(builder = AutoValue_ArtistInfo.Builder.class) +public abstract class ArtistInfo implements Parcelable { - 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.big = in.readString(); - cover.small = in.readString(); + public static Builder builder() { + return new AutoValue_ArtistInfo.Builder(); } - 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]; - } - }; - - @Override - public int describeContents() { - return 0; - } + public static ArtistInfo create(@JsonProperty("id") long id, + @JsonProperty("name") String name, + @JsonProperty("genres") List genres, + @JsonProperty("tracks") long tracks, + @JsonProperty("albums") long albums, + @JsonProperty("link") @Nullable String link, + @JsonProperty("description") String description, + @JsonProperty("cover") Cover cover) { + return builder().id(id) + .name(name) + .genres(genres) + .tracks(tracks) + .albums(albums) + .link(link) + .description(description) + .cover(cover) + .build(); - @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.big); - dest.writeString(cover.small); } - public class Cover { - private String small; - private String big; + // Properties + @JsonProperty("id") + public abstract long id(); - public Cover() { - } + @JsonProperty("name") + public abstract String name(); - public String getSmall() { - return small; - } + @JsonProperty("genres") + public abstract List genres(); - public String getBig() { - return big; - } - } + @JsonProperty("tracks") + public abstract long tracks(); + @JsonProperty("albums") + public abstract long albums(); - @Override - public String toString() { - return "ArtistInfo{" + - "id=" + id + - ", name='" + name + '\'' + - ", genres=" + genres + - ", albums=" + albums + - ", link='" + link + '\'' + - ", description='" + description + '\'' + - ", cover=" + cover + - '}'; - } + @JsonProperty("link") + @Nullable + public abstract String link(); - public String getName() { - return name; - } + @JsonProperty("description") + public abstract String description(); - public List getGenres() { - return genres; - } + @JsonProperty("cover") + public abstract Cover cover(); - public Cover getCover() { - return cover; - } - public long getAlbums() { - return albums; - } + @AutoValue.Builder + @JsonPOJOBuilder(withPrefix = "") + public static abstract class Builder { + @JsonProperty("id") + public abstract Builder id(long id); - public String getDescription() { - return description; - } + @JsonProperty("name") + public abstract Builder name(String name); + + @JsonProperty("genres") + public abstract Builder genres(List genres); + + @JsonProperty("tracks") + public abstract Builder tracks(long tracks); + + @JsonProperty("albums") + public abstract Builder albums(long albums); + + @JsonProperty("link") + public abstract Builder link(String link); + + @JsonProperty("description") + public abstract Builder description(String description); + + @JsonProperty("cover") + public abstract Builder cover(Cover cover); - public long getTracks() { - return tracks; + @JsonCreator + public abstract ArtistInfo build(); } } diff --git a/app/src/main/java/com/bobrusha/android/artists/model/Cover.java b/app/src/main/java/com/bobrusha/android/artists/model/Cover.java new file mode 100644 index 0000000..45b6afe --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/model/Cover.java @@ -0,0 +1,28 @@ +package com.bobrusha.android.artists.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/com/bobrusha/android/artists/receiver/MusicIntentReceiver.java b/app/src/main/java/com/bobrusha/android/artists/receiver/MusicIntentReceiver.java new file mode 100644 index 0000000..eeab705 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/receiver/MusicIntentReceiver.java @@ -0,0 +1,74 @@ +package com.bobrusha.android.artists.receiver; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.media.AudioManager; +import android.net.Uri; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; +import android.support.v7.app.NotificationCompat; + +import com.bobrusha.android.artists.R; + +/** + * Created by Aleksandra on 03/08/16. + */ +public class MusicIntentReceiver extends BroadcastReceiver { + private static final String OPEN_IN_MARKET = "market://details?id="; + private static final String YA_MUSIC_PACKAGE_NAME = "ru.yandex.music"; + private static final String YA_RADIO_PACKAGE_NAME = "ru.yandex.radio"; + private static final int NOTIFICATION_ID = 1; + + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(AudioManager.ACTION_HEADSET_PLUG)) { + int state = intent.getIntExtra("state", -1); + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + switch (state) { + case 0: + notificationManager.cancel(NOTIFICATION_ID); + break; + case 1: + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context); + notificationBuilder.setContentTitle(context.getString(R.string.notification_title)) + .setContentText(context.getString(R.string.notification_text)) + .setSmallIcon(R.drawable.ic_earphones); + + createAction(context, notificationBuilder, YA_MUSIC_PACKAGE_NAME, + R.drawable.ic_note, R.drawable.ic_download, R.string.open_ya_music); + createAction(context, notificationBuilder, YA_RADIO_PACKAGE_NAME, + R.drawable.ic_radio, R.drawable.ic_download, R.string.open_ya_radio); + + Notification notification = + (new NotificationCompat.BigTextStyle(notificationBuilder)).bigText( + context.getString(R.string.notification_text) + ).build(); + notificationManager.notify(NOTIFICATION_ID, notification); + break; + } + } + } + + public void createAction(Context context, NotificationCompat.Builder builder, String packageName, + @DrawableRes int icOpen, @DrawableRes int icDownload, @StringRes int name) { + PackageManager manager = context.getPackageManager(); + Intent intent = manager.getLaunchIntentForPackage(packageName); + if (intent != null) { + intent.addCategory(Intent.CATEGORY_LAUNCHER); + PendingIntent pi = PendingIntent.getActivity(context, 0, intent, 0); + builder.addAction(icOpen, context.getString(name), pi); + } else { + PendingIntent pi = PendingIntent.getActivity(context, 0, new Intent( + Intent.ACTION_VIEW, Uri.parse(OPEN_IN_MARKET + packageName)), 0); + builder.addAction(icDownload, context.getString(name), pi); + } + } + +} diff --git a/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewAdapter.java b/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewAdapter.java index 391ddc9..700c73b 100644 --- a/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewAdapter.java +++ b/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewAdapter.java @@ -1,5 +1,6 @@ package com.bobrusha.android.artists.recycler_view; +import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -7,37 +8,47 @@ import com.bobrusha.android.artists.R; import com.bobrusha.android.artists.model.ArtistInfo; +import com.bobrusha.android.artists.ui.MainActivity; import java.util.List; /** - * * @author Aleksandra Bobrova */ public class ArtistPreviewAdapter extends RecyclerView.Adapter { - private List mDataset; - + private List dataset; @Override public ArtistPreviewViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.artist_preview, parent, false); - return new ArtistPreviewViewHolder(v); + final View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.artist_preview, parent, false); + final ArtistPreviewViewHolder h = new ArtistPreviewViewHolder(v); + v.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + int adapterPosition = h.getAdapterPosition(); + if (adapterPosition != RecyclerView.NO_POSITION) { + final Context context = view.getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).onArtistSelected(dataset.get(adapterPosition)); + } + } + } + }); + return h; } @Override public void onBindViewHolder(ArtistPreviewViewHolder holder, int position) { - if (position < mDataset.size()) { - holder.bind(mDataset.get(position)); - } + holder.bind(dataset.get(position)); } @Override public int getItemCount() { - return mDataset == null ? 0 : mDataset.size(); + return dataset == null ? 0 : dataset.size(); } public void setDataset(List dataset) { - mDataset = dataset; + this.dataset = dataset; notifyDataSetChanged(); } } diff --git a/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewViewHolder.java b/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewViewHolder.java index 4d2f3fa..8da7887 100644 --- a/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewViewHolder.java +++ b/app/src/main/java/com/bobrusha/android/artists/recycler_view/ArtistPreviewViewHolder.java @@ -1,56 +1,52 @@ package com.bobrusha.android.artists.recycler_view; -import android.content.Context; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.View; import android.widget.ImageView; import android.widget.TextView; -import com.bobrusha.android.artists.BusProvider; import com.bobrusha.android.artists.R; -import com.bobrusha.android.artists.event.ArtistPreviewOnClickEvent; import com.bobrusha.android.artists.model.ArtistInfo; import com.squareup.picasso.Picasso; +import butterknife.BindView; +import butterknife.ButterKnife; + /** - * * @author Aleksandra Bobrova */ public class ArtistPreviewViewHolder extends RecyclerView.ViewHolder { - private final Context context; - private final TextView mArtistNameView; - private final TextView mGenreTextView; - private final TextView mAlbumsTextView; - private final ImageView mImageView; + @BindView(R.id.preview_artist_name) + TextView artistNameView; + + @BindView(R.id.preview_artist_genre) + TextView genreTextView; + + @BindView(R.id.preview_artist_albums) + TextView albumsTextView; + + @BindView(R.id.preview_artist_img) + ImageView coverImageView; public ArtistPreviewViewHolder(View itemView) { super(itemView); - context = itemView.getContext(); - mArtistNameView = (TextView) itemView.findViewById(R.id.preview_artist_name); - mGenreTextView = (TextView) itemView.findViewById(R.id.preview_artist_genre); - mAlbumsTextView = (TextView) itemView.findViewById(R.id.preview_artist_albums); - mImageView = (ImageView) itemView.findViewById(R.id.preview_artist_img); + ButterKnife.bind(this, itemView); } public void bind(final ArtistInfo artistInfo) { - mArtistNameView.setText(artistInfo.getName()); - - String genres = TextUtils.join(", ", artistInfo.getGenres()); - mGenreTextView.setText(genres); + artistNameView.setText(artistInfo.name()); - String pattern = context.getString(R.string.amount_of_albums_and_tracks); - mAlbumsTextView.setText(String.format(pattern, artistInfo.getAlbums(), artistInfo.getTracks())); + if (artistInfo.genres() != null) { + String genres = TextUtils.join(", ", artistInfo.genres()); + genreTextView.setText(genres); + } - Picasso.with(context) - .load(artistInfo.getCover().getSmall()) - .into(mImageView); + String pattern = artistNameView.getContext().getString(R.string.amount_of_albums_and_tracks); + albumsTextView.setText(String.format(pattern, artistInfo.albums(), artistInfo.tracks())); - itemView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - BusProvider.getInstance().post(new ArtistPreviewOnClickEvent(artistInfo)); - } - }); + Picasso.with(coverImageView.getContext()) + .load(artistInfo.cover().getSmall()) + .into(coverImageView); } } diff --git a/app/src/main/java/com/bobrusha/android/artists/recycler_view/DividerItemDecoration.java b/app/src/main/java/com/bobrusha/android/artists/recycler_view/DividerItemDecoration.java index 92debe4..05b8968 100644 --- a/app/src/main/java/com/bobrusha/android/artists/recycler_view/DividerItemDecoration.java +++ b/app/src/main/java/com/bobrusha/android/artists/recycler_view/DividerItemDecoration.java @@ -14,10 +14,10 @@ * @author Aleksandra Bobrova */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { - private final Drawable mDivider; + private final Drawable divider; public DividerItemDecoration(Context context, int dividerId) { - mDivider = ContextCompat.getDrawable(context, dividerId); + divider = ContextCompat.getDrawable(context, dividerId); } @Override @@ -28,7 +28,7 @@ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, Recycle return; } - outRect.top = mDivider.getIntrinsicHeight(); + outRect.top = divider.getIntrinsicHeight(); } @Override @@ -42,10 +42,10 @@ public void onDraw(Canvas canvas, RecyclerView parent, RecyclerView.State state) RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); int dividerTop = child.getBottom() + params.bottomMargin; - int dividerBottom = dividerTop + mDivider.getIntrinsicHeight(); + int dividerBottom = dividerTop + divider.getIntrinsicHeight(); - mDivider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom); - mDivider.draw(canvas); + divider.setBounds(dividerLeft, dividerTop, dividerRight, dividerBottom); + divider.draw(canvas); } } } diff --git a/app/src/main/java/com/bobrusha/android/artists/ui/MainActivity.java b/app/src/main/java/com/bobrusha/android/artists/ui/MainActivity.java new file mode 100644 index 0000000..43e1a4e --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/ui/MainActivity.java @@ -0,0 +1,152 @@ +package com.bobrusha.android.artists.ui; + +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.NavigationView; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.MenuItem; + +import com.bobrusha.android.artists.Constants; +import com.bobrusha.android.artists.R; +import com.bobrusha.android.artists.model.ArtistInfo; +import com.bobrusha.android.artists.receiver.MusicIntentReceiver; +import com.bobrusha.android.artists.ui.fragment.AboutFragment; +import com.bobrusha.android.artists.ui.fragment.ArtistDetailFragment; +import com.bobrusha.android.artists.ui.fragment.MainFragment; +import com.bobrusha.android.artists.ui.fragment.SettingsFragment; + +import butterknife.BindView; +import butterknife.ButterKnife; + + +/** + * Main Activity for managing fragments. + * + * @author Aleksandra Bobrova + */ +public class MainActivity extends AppCompatActivity { + @BindView(R.id.nvView) + NavigationView navigationView; + + @BindView(R.id.drawer_layout) + DrawerLayout drawerLayout; + + @BindView(R.id.toolbar) + Toolbar toolbar; + + private ActionBarDrawerToggle drawerToggle; + + private MusicIntentReceiver receiver; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + if (savedInstanceState == null) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.add(R.id.container_for_fragment, new MainFragment()); + transaction.commit(); + } + + ButterKnife.bind(this); + setSupportActionBar(toolbar); + setupDrawerContent(navigationView); + + drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, + R.string.drawer_open, R.string.drawer_close); + drawerLayout.addDrawerListener(drawerToggle); + + receiver = new MusicIntentReceiver(); + } + + @Override + protected void onPostCreate(@Nullable Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + drawerToggle.syncState(); + } + + @Override + protected void onResume() { + super.onResume(); + + IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG); + registerReceiver(receiver, filter); + } + + @Override + protected void onPause() { + super.onPause(); + unregisterReceiver(receiver); + } + + + /** + * Method that calling then user chose musician. + * + * @param artistInfo - object with information for detailed fragment. + */ + public void onArtistSelected(ArtistInfo artistInfo) { + ArtistDetailFragment fragment = new ArtistDetailFragment(); + Bundle args = new Bundle(); + args.putParcelable(Constants.EXTRA_ARTIST, artistInfo); + fragment.setArguments(args); + + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + transaction.replace(R.id.container_for_fragment, fragment); + transaction.addToBackStack(null); + transaction.commit(); + } + + private void setupDrawerContent(NavigationView navigationView) { + navigationView.setNavigationItemSelectedListener( + new NavigationView.OnNavigationItemSelectedListener() { + @Override + public boolean onNavigationItemSelected(MenuItem menuItem) { + selectDrawerItem(menuItem); + return true; + } + }); + } + + private void selectDrawerItem(MenuItem menuItem) { + Fragment fragment; + + switch (menuItem.getItemId()) { + case R.id.nav_home: + fragment = new MainFragment(); + break; + case R.id.nav_settings: + fragment = new SettingsFragment(); + break; + case R.id.nav_about_program: + fragment = new AboutFragment(); + break; + default: + fragment = new MainFragment(); + } + + drawerLayout.closeDrawers(); + FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager.beginTransaction().replace(R.id.container_for_fragment, fragment).commit(); + menuItem.setChecked(true); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (drawerToggle.onOptionsItemSelected(item)) { + return true; + } + return super.onOptionsItemSelected(item); + } + + +} diff --git a/app/src/main/java/com/bobrusha/android/artists/ui/fragment/AboutFragment.java b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/AboutFragment.java new file mode 100644 index 0000000..80a6d53 --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/AboutFragment.java @@ -0,0 +1,57 @@ +package com.bobrusha.android.artists.ui.fragment; + +import android.content.ActivityNotFoundException; +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; + +import com.bobrusha.android.artists.R; + +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; + +/** + * Created by Aleksandra on 16/07/16. + */ +public class AboutFragment extends Fragment { + private static final String EMAIL_TO = "bobrova.aleksand@gmail.com"; + private static final String EMAIL_SUBJECT = "Artists app"; + private static final String EMAIL_TYPE = "message/rfc822"; + + private static final Intent intent = new Intent(Intent.ACTION_SEND) + .setType(EMAIL_TYPE) + .putExtra(Intent.EXTRA_EMAIL, new String[]{EMAIL_TO}) + .putExtra(Intent.EXTRA_SUBJECT, EMAIL_SUBJECT); + + @BindView(R.id.btn_send_email_to_devs) + Button sendToButton; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_about, container, false); + ButterKnife.bind(this, v); + return v; + + } + + @OnClick(R.id.btn_send_email_to_devs) + public void onSendEmailClick() { + try { + startActivity(Intent.createChooser(intent, getString(R.string.send_email_chooser))); + } catch (ActivityNotFoundException ex) { + Snackbar snackbar = Snackbar.make(getActivity().findViewById(R.id.refresh_layout), + getString(R.string.no_email_client), + Snackbar.LENGTH_SHORT); + snackbar.show(); + } + + } +} diff --git a/app/src/main/java/com/bobrusha/android/artists/ui/fragment/ArtistDetailFragment.java b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/ArtistDetailFragment.java new file mode 100644 index 0000000..9dbb99b --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/ArtistDetailFragment.java @@ -0,0 +1,87 @@ +package com.bobrusha.android.artists.ui.fragment; + + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.bobrusha.android.artists.Constants; +import com.bobrusha.android.artists.R; +import com.bobrusha.android.artists.model.ArtistInfo; +import com.squareup.picasso.Callback; +import com.squareup.picasso.Picasso; + +import butterknife.BindView; +import butterknife.ButterKnife; + +/** + * Created by Aleksandra on 15/07/16. + */ +public class ArtistDetailFragment extends Fragment { + private ArtistInfo artist; + + @BindView(R.id.artist_detail_genre_text) + TextView genre; + + @BindView(R.id.artist_detail_albums_and_tracks) + TextView albumsAndTracks; + + @BindView(R.id.artist_detail_biography_text) + TextView bio; + + @BindView(R.id.artist_detail_big_img) + ImageView imageView; + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Bundle args = getArguments(); + artist = args.getParcelable(Constants.EXTRA_ARTIST); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + final View v = inflater.inflate(R.layout.fragment_artist_detail, container, false); + ButterKnife.bind(this, v); + + imageView = (ImageView) v.findViewById(R.id.artist_detail_big_img); + Picasso.with(imageView.getContext()) + .load(artist.cover().getBig()) + .into(imageView, new Callback() { + @Override + public void onSuccess() { + imageView.setVisibility(View.VISIBLE); + } + + @Override + public void onError() { + //Stop progressBar and show image + v.findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE); + v.findViewById(R.id.artist_detail_no_image).setVisibility(View.VISIBLE); + + } + }); + + genre = (TextView) v.findViewById(R.id.artist_detail_genre_text); + genre.setText(TextUtils.join(", ", artist.genres())); + + albumsAndTracks = (TextView) v.findViewById(R.id.artist_detail_albums_and_tracks); + String pattern = getString(R.string.artist_detail_albums_and_tracks); + albumsAndTracks.setText( + String.format(pattern, artist.albums(), artist.tracks()) + ); + + bio = (TextView) v.findViewById(R.id.artist_detail_biography_text); + bio.setText(artist.description()); + + return v; + } +} diff --git a/app/src/main/java/com/bobrusha/android/artists/ui/fragment/MainFragment.java b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/MainFragment.java new file mode 100644 index 0000000..0ed118f --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/MainFragment.java @@ -0,0 +1,127 @@ +package com.bobrusha.android.artists.ui.fragment; + + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.design.widget.Snackbar; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v4.widget.SwipeRefreshLayout; +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 com.bobrusha.android.artists.ArtistInfoLoader; +import com.bobrusha.android.artists.CacheLoader; +import com.bobrusha.android.artists.Constants; +import com.bobrusha.android.artists.R; +import com.bobrusha.android.artists.model.ArtistInfo; +import com.bobrusha.android.artists.recycler_view.ArtistPreviewAdapter; +import com.bobrusha.android.artists.recycler_view.DividerItemDecoration; + +import java.util.List; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class MainFragment extends Fragment implements LoaderManager.LoaderCallbacks> { + private List newData; + + @BindView(R.id.recycler_view_artists) + RecyclerView recyclerView; + + @BindView(R.id.refresh_layout) + SwipeRefreshLayout swipeRefreshLayout; + + private ArtistPreviewAdapter adapter; + private Snackbar snackbar; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.fragment_main, container, false); + ButterKnife.bind(this, v); + + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + + adapter = new ArtistPreviewAdapter(); + recyclerView.setAdapter(adapter); + + recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), R.drawable.divider)); + + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + getActivity().getSupportLoaderManager() + .restartLoader(Constants.ARTIST_INFO_LOADER_ID, null, MainFragment.this); + getActivity().getSupportLoaderManager() + .restartLoader(Constants.CACHE_LOADER_ID, null, MainFragment.this); + + swipeRefreshLayout.setRefreshing(false); + } + }); + + return v; + } + + @Override + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + getLoaderManager().initLoader(Constants.ARTIST_INFO_LOADER_ID, null, this); + getLoaderManager().initLoader(Constants.CACHE_LOADER_ID, null, this); + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + switch (id) { + case Constants.ARTIST_INFO_LOADER_ID: + newData = null; + return new ArtistInfoLoader(getActivity()); + case Constants.CACHE_LOADER_ID: + return new CacheLoader(getActivity()); + } + return null; + } + + @Override + public void onLoadFinished(Loader> loader, List data) { + swipeRefreshLayout.setRefreshing(false); + + if (loader.getId() == Constants.CACHE_LOADER_ID && newData == null) { + adapter.setDataset(data); + return; + } + + // Show snackBar if no data was loaded + if (data == null || data.isEmpty()) { + if (newData != null && !newData.isEmpty()) { + adapter.setDataset(newData); + } else { + if (snackbar == null) { + snackbar = Snackbar.make(swipeRefreshLayout, + R.string.no_data_to_display, + Snackbar.LENGTH_INDEFINITE); + } + snackbar.show(); + } + } else { + if (loader.getId() == Constants.ARTIST_INFO_LOADER_ID) { + newData = data; + } + adapter.setDataset(data); + if (snackbar != null) { + snackbar.dismiss(); + } + } + + } + + @Override + public void onLoaderReset(Loader> loader) { + + } +} diff --git a/app/src/main/java/com/bobrusha/android/artists/ui/fragment/SettingsFragment.java b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/SettingsFragment.java new file mode 100644 index 0000000..775710c --- /dev/null +++ b/app/src/main/java/com/bobrusha/android/artists/ui/fragment/SettingsFragment.java @@ -0,0 +1,18 @@ +package com.bobrusha.android.artists.ui.fragment; + +import android.os.Bundle; +import android.support.v7.preference.PreferenceFragmentCompat; + + +import com.bobrusha.android.artists.R; + +/** + * Created by Aleksandra on 19/07/16. + */ +public class SettingsFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.settings); + } +} diff --git a/app/src/main/res/drawable-hdpi-v11/ic_download.png b/app/src/main/res/drawable-hdpi-v11/ic_download.png new file mode 100644 index 0000000..0524b00 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_download.png differ diff --git a/app/src/main/res/drawable-hdpi-v11/ic_earphones.png b/app/src/main/res/drawable-hdpi-v11/ic_earphones.png new file mode 100644 index 0000000..7e49b9f Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_earphones.png differ diff --git a/app/src/main/res/drawable-hdpi-v11/ic_note.png b/app/src/main/res/drawable-hdpi-v11/ic_note.png new file mode 100644 index 0000000..c6ddd05 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_note.png differ diff --git a/app/src/main/res/drawable-hdpi-v11/ic_radio.png b/app/src/main/res/drawable-hdpi-v11/ic_radio.png new file mode 100644 index 0000000..639e059 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_radio.png differ diff --git a/app/src/main/res/drawable-hdpi-v9/ic_download.png b/app/src/main/res/drawable-hdpi-v9/ic_download.png new file mode 100644 index 0000000..ddbd0ce Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v9/ic_download.png differ diff --git a/app/src/main/res/drawable-hdpi-v9/ic_earphones.png b/app/src/main/res/drawable-hdpi-v9/ic_earphones.png new file mode 100644 index 0000000..6470fb7 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v9/ic_earphones.png differ diff --git a/app/src/main/res/drawable-hdpi-v9/ic_note.png b/app/src/main/res/drawable-hdpi-v9/ic_note.png new file mode 100644 index 0000000..dc961e5 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v9/ic_note.png differ diff --git a/app/src/main/res/drawable-hdpi-v9/ic_radio.png b/app/src/main/res/drawable-hdpi-v9/ic_radio.png new file mode 100644 index 0000000..00867a2 Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v9/ic_radio.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_download.png b/app/src/main/res/drawable-hdpi/ic_download.png new file mode 100644 index 0000000..9f1d8ad Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_download.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_earphones.png b/app/src/main/res/drawable-hdpi/ic_earphones.png new file mode 100644 index 0000000..d8db6f3 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_earphones.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_note.png b/app/src/main/res/drawable-hdpi/ic_note.png new file mode 100644 index 0000000..05a8648 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_note.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_radio.png b/app/src/main/res/drawable-hdpi/ic_radio.png new file mode 100644 index 0000000..2a51a84 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_radio.png differ diff --git a/app/src/main/res/drawable-mdpi-v11/ic_download.png b/app/src/main/res/drawable-mdpi-v11/ic_download.png new file mode 100644 index 0000000..a119cd4 Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_download.png differ diff --git a/app/src/main/res/drawable-mdpi-v11/ic_earphones.png b/app/src/main/res/drawable-mdpi-v11/ic_earphones.png new file mode 100644 index 0000000..743719c Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_earphones.png differ diff --git a/app/src/main/res/drawable-mdpi-v11/ic_note.png b/app/src/main/res/drawable-mdpi-v11/ic_note.png new file mode 100644 index 0000000..9f5929e Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_note.png differ diff --git a/app/src/main/res/drawable-mdpi-v11/ic_radio.png b/app/src/main/res/drawable-mdpi-v11/ic_radio.png new file mode 100644 index 0000000..b2a0100 Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_radio.png differ diff --git a/app/src/main/res/drawable-mdpi-v9/ic_download.png b/app/src/main/res/drawable-mdpi-v9/ic_download.png new file mode 100644 index 0000000..49d494d Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v9/ic_download.png differ diff --git a/app/src/main/res/drawable-mdpi-v9/ic_earphones.png b/app/src/main/res/drawable-mdpi-v9/ic_earphones.png new file mode 100644 index 0000000..0dd64ed Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v9/ic_earphones.png differ diff --git a/app/src/main/res/drawable-mdpi-v9/ic_note.png b/app/src/main/res/drawable-mdpi-v9/ic_note.png new file mode 100644 index 0000000..4fc43d3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v9/ic_note.png differ diff --git a/app/src/main/res/drawable-mdpi-v9/ic_radio.png b/app/src/main/res/drawable-mdpi-v9/ic_radio.png new file mode 100644 index 0000000..b581a2a Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v9/ic_radio.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_download.png b/app/src/main/res/drawable-mdpi/ic_download.png new file mode 100644 index 0000000..acd09cb Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_download.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_earphones.png b/app/src/main/res/drawable-mdpi/ic_earphones.png new file mode 100644 index 0000000..19e6f23 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_earphones.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_note.png b/app/src/main/res/drawable-mdpi/ic_note.png new file mode 100644 index 0000000..6c87df6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_note.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_radio.png b/app/src/main/res/drawable-mdpi/ic_radio.png new file mode 100644 index 0000000..1c94109 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_radio.png differ diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_download.png b/app/src/main/res/drawable-xhdpi-v11/ic_download.png new file mode 100644 index 0000000..180bdcd Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_download.png differ diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_earphones.png b/app/src/main/res/drawable-xhdpi-v11/ic_earphones.png new file mode 100644 index 0000000..60c608e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_note.png b/app/src/main/res/drawable-xhdpi-v11/ic_note.png new file mode 100644 index 0000000..70a17a3 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_note.png differ diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_radio.png b/app/src/main/res/drawable-xhdpi-v11/ic_radio.png new file mode 100644 index 0000000..e6fe62d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_radio.png differ diff --git a/app/src/main/res/drawable-xhdpi-v9/ic_download.png b/app/src/main/res/drawable-xhdpi-v9/ic_download.png new file mode 100644 index 0000000..6313634 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v9/ic_download.png differ diff --git a/app/src/main/res/drawable-xhdpi-v9/ic_earphones.png b/app/src/main/res/drawable-xhdpi-v9/ic_earphones.png new file mode 100644 index 0000000..456b28c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v9/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xhdpi-v9/ic_note.png b/app/src/main/res/drawable-xhdpi-v9/ic_note.png new file mode 100644 index 0000000..68f839a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v9/ic_note.png differ diff --git a/app/src/main/res/drawable-xhdpi-v9/ic_radio.png b/app/src/main/res/drawable-xhdpi-v9/ic_radio.png new file mode 100644 index 0000000..c38eef8 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v9/ic_radio.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_download.png b/app/src/main/res/drawable-xhdpi/ic_download.png new file mode 100644 index 0000000..024442a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_download.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_earphones.png b/app/src/main/res/drawable-xhdpi/ic_earphones.png new file mode 100644 index 0000000..5e4c3b4 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_note.png b/app/src/main/res/drawable-xhdpi/ic_note.png new file mode 100644 index 0000000..9118a25 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_note.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_radio.png b/app/src/main/res/drawable-xhdpi/ic_radio.png new file mode 100644 index 0000000..a7b9576 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_radio.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_download.png b/app/src/main/res/drawable-xxhdpi-v11/ic_download.png new file mode 100644 index 0000000..8e54cce Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_download.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_earphones.png b/app/src/main/res/drawable-xxhdpi-v11/ic_earphones.png new file mode 100644 index 0000000..5e9d595 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_note.png b/app/src/main/res/drawable-xxhdpi-v11/ic_note.png new file mode 100644 index 0000000..0374073 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_note.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_radio.png b/app/src/main/res/drawable-xxhdpi-v11/ic_radio.png new file mode 100644 index 0000000..9c586d0 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_radio.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v9/ic_download.png b/app/src/main/res/drawable-xxhdpi-v9/ic_download.png new file mode 100644 index 0000000..ccc41d1 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v9/ic_download.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v9/ic_earphones.png b/app/src/main/res/drawable-xxhdpi-v9/ic_earphones.png new file mode 100644 index 0000000..8a877aa Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v9/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v9/ic_note.png b/app/src/main/res/drawable-xxhdpi-v9/ic_note.png new file mode 100644 index 0000000..8968741 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v9/ic_note.png differ diff --git a/app/src/main/res/drawable-xxhdpi-v9/ic_radio.png b/app/src/main/res/drawable-xxhdpi-v9/ic_radio.png new file mode 100644 index 0000000..681a8a9 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v9/ic_radio.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_download.png b/app/src/main/res/drawable-xxhdpi/ic_download.png new file mode 100644 index 0000000..1c8f804 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_download.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_earphones.png b/app/src/main/res/drawable-xxhdpi/ic_earphones.png new file mode 100644 index 0000000..c6f0c19 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_earphones.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_note.png b/app/src/main/res/drawable-xxhdpi/ic_note.png new file mode 100644 index 0000000..08b5b2b Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_note.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_radio.png b/app/src/main/res/drawable-xxhdpi/ic_radio.png new file mode 100644 index 0000000..3d3ebc8 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_radio.png differ diff --git a/app/src/main/res/drawable/divider.xml b/app/src/main/res/drawable/divider.xml index 80b8c8c..edddbb2 100644 --- a/app/src/main/res/drawable/divider.xml +++ b/app/src/main/res/drawable/divider.xml @@ -2,6 +2,6 @@ - + android:height="1dp"/> + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index b3cbb43..3f8245d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,16 +1,38 @@ - - - - + + + android:layout_height="match_parent" + android:orientation="vertical"> + + + + + + + + + - + + + diff --git a/app/src/main/res/layout/artist_preview.xml b/app/src/main/res/layout/artist_preview.xml index 3cb7189..637c715 100644 --- a/app/src/main/res/layout/artist_preview.xml +++ b/app/src/main/res/layout/artist_preview.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml new file mode 100644 index 0000000..022dc98 --- /dev/null +++ b/app/src/main/res/layout/fragment_about.xml @@ -0,0 +1,31 @@ + + + + + + + +