diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 8598a75..0000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-Yapplication
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
deleted file mode 100644
index 97626ba..0000000
--- a/.idea/encodings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 2ab1e27..4c73708 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -3,22 +3,10 @@
diff --git a/app/.gitignore b/app/.gitignore
index 796b96d..09fb41b 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1 +1,2 @@
/build
+.idea/*
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index e4ec7db..9f51b5b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,10 +2,22 @@ apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'me.tatarka.retrolambda'
+def keystorePropertiesFile = rootProject.file("keystore.properties")
+def keystoreProperties = new Properties()
+keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
+
android {
compileSdkVersion 23
- buildToolsVersion "23.0.2"
-
+// signingConfigs {
+// Yappl {
+// keyAlias keystoreProperties['keyAlias']
+// keyPassword keystoreProperties['keyPassword']
+// storeFile file(keystoreProperties['storeFile'])
+// storePassword keystoreProperties['storePassword']
+// }
+// }
+ compileSdkVersion 23
+ buildToolsVersion "23.0.3"
defaultConfig {
applicationId "ru.aleien.yapplication"
minSdkVersion 15
@@ -15,7 +27,7 @@ android {
}
buildTypes {
release {
- minifyEnabled false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
@@ -24,12 +36,6 @@ android {
}
}
- sourceSets {
- androidTest {
- setRoot('src/test')
- }
- }
-
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -38,34 +44,49 @@ android {
dependencies {
ext.supportVersion = '23.3.0'
- compile fileTree(dir: 'libs', include: ['*.jar'])
- compile "com.android.support:support-v4:$supportVersion"
- compile "com.android.support:appcompat-v7:$supportVersion"
- compile "com.android.support:design:$supportVersion"
+ compile fileTree(include: ['*.jar'], dir: 'libs')
+ compile 'com.android.support:support-v4:24.1.1'
+ compile 'com.android.support:appcompat-v7:24.1.1'
+ compile 'com.android.support:design:24.1.1'
// Annotation heaven
- compile 'com.jakewharton:butterknife:7.0.1'
+ compile 'com.jakewharton:butterknife:8.2.1'
+ apt 'com.jakewharton:butterknife-compiler:8.2.1'
compile 'javax.annotation:jsr250-api:1.0'
// UI
- compile "com.android.support:cardview-v7:$supportVersion"
- compile "com.android.support:recyclerview-v7:$supportVersion"
+ compile 'com.android.support:cardview-v7:24.1.1'
+ compile 'com.android.support:recyclerview-v7:24.1.1'
// Testing
testCompile 'junit:junit:4.12'
- androidTestCompile "com.android.support:support-annotations:$supportVersion"
- androidTestCompile 'com.android.support.test:runner:0.4.1'
- testCompile "org.robolectric:robolectric:3.0"
- testCompile "org.mockito:mockito-core:1.10.19"
+ androidTestCompile "com.android.support:support-annotations:24.1.1"
+ androidTestCompile 'com.android.support.test:runner:0.5'
+ testCompile 'org.mockito:mockito-core:2.0.99-beta'
+ testCompile "org.robolectric:robolectric:3.1.2"
+ testCompile 'org.robolectric:shadows-support-v4:3.1.2'
// Network
compile 'com.squareup.okhttp:okhttp:2.7.5'
- compile 'com.squareup.okhttp3:logging-interceptor:3.0.1'
- compile 'com.squareup.retrofit2:converter-gson:2.0.0'
- compile 'com.squareup.retrofit2:retrofit:2.0.0'
-
+ compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
+ compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
+ compile 'com.squareup.retrofit2:converter-gson:2.1.0'
+ compile 'com.squareup.retrofit2:retrofit:2.1.0'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta2'
// Image processor
compile 'com.github.bumptech.glide:glide:3.7.0'
+
+ // DI
+ compile 'com.google.dagger:dagger:2.6'
+ apt 'com.google.dagger:dagger-compiler:2.6'
+ provided 'javax.annotation:jsr250-api:1.0'
+
+ // Rx
+ compile 'io.reactivex:rxandroid:1.2.1'
+ compile 'io.reactivex:rxjava:1.1.8'
+
+ debugCompile 'com.facebook.stetho:stetho:1.2.0'
+ compile 'com.jakewharton.timber:timber:4.1.2'
+
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 0a0c3b5..49e0649 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -15,3 +15,26 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+
+# Butterknife
+-keep public class * implements butterknife.internal.ViewBinder { public (); }
+
+# Prevent obfuscation of types which use ButterKnife annotations since the simple name
+# is used to reflectively look up the generated ViewBinder.
+-keep class butterknife.*
+-keepclasseswithmembernames class * { @butterknife.* ; }
+-keepclasseswithmembernames class * { @butterknife.* ; }
+-keepnames class * { @butterknife.Bind *;}
+
+# Dagger
+-keepclassmembers,allowobfuscation class * {
+ @javax.inject.* *;
+ @dagger.* *;
+ ();
+}
+
+-keep class javax.inject.** { *; }
+-keep class **$$ModuleAdapter
+-keep class **$$InjectAdapter
+-keep class **$$StaticInjection
+-keep class dagger.** { *; }
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cd8d13b..bdf3034 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,24 +1,33 @@
+ package="ru.aleien.yapplication">
-
-
+
+
+
-
+
-
+
-
+
+
+
diff --git a/app/src/main/java/ru/aleien/yapplication/App.java b/app/src/main/java/ru/aleien/yapplication/App.java
new file mode 100644
index 0000000..c91dcac
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/App.java
@@ -0,0 +1,30 @@
+package ru.aleien.yapplication;
+
+import android.app.Application;
+
+import com.facebook.stetho.Stetho;
+
+import ru.aleien.yapplication.di.AppComponent;
+import ru.aleien.yapplication.di.AppModule;
+import ru.aleien.yapplication.di.DaggerAppComponent;
+import timber.log.Timber;
+
+public class App extends Application {
+ private AppComponent component;
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree());
+ Stetho.initializeWithDefaults(this.getApplicationContext());
+ component = DaggerAppComponent.builder()
+ .appModule(new AppModule(this))
+ .build();
+
+ }
+
+ public AppComponent dagger() {
+ return component;
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/ArtistsPresenter.java b/app/src/main/java/ru/aleien/yapplication/ArtistsPresenter.java
index 0496e90..0c4ef32 100644
--- a/app/src/main/java/ru/aleien/yapplication/ArtistsPresenter.java
+++ b/app/src/main/java/ru/aleien/yapplication/ArtistsPresenter.java
@@ -1,14 +1,17 @@
package ru.aleien.yapplication;
-import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v7.widget.RecyclerView;
+import android.util.Log;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.List;
+import javax.inject.Inject;
+
import ru.aleien.yapplication.base.BasePresenter;
+import ru.aleien.yapplication.database.DBBackend;
import ru.aleien.yapplication.dataprovider.ArtistsProvider;
import ru.aleien.yapplication.dataprovider.WebArtistsProvider;
import ru.aleien.yapplication.model.Artist;
@@ -17,6 +20,10 @@
import ru.aleien.yapplication.screens.list.ArtistsListView;
import ru.aleien.yapplication.screens.list.ArtistsRecyclerFragment;
import ru.aleien.yapplication.utils.adapters.ArtistsRecyclerAdapter;
+import rx.Completable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+import timber.log.Timber;
/**
* Created by aleien on 09.04.16.
@@ -25,17 +32,33 @@
*/
public class ArtistsPresenter extends BasePresenter implements ArtistsRequester, ArtistClickHandler, Serializable {
ArtistsProvider artistsProvider;
+ private final DBBackend dbSource;
private WeakReference> artistsListView;
private WeakReference currentFragment;
- public ArtistsPresenter(Context context) {
- artistsProvider = new WebArtistsProvider(this, context);
+ @Inject
+ public ArtistsPresenter(DBBackend dbSource,
+ // Как здесь получать интерфейс?
+ WebArtistsProvider artistsProvider) {
+ this.dbSource = dbSource;
+ this.artistsProvider = artistsProvider;
}
@Override
public void takeListView(ArtistsListView list) {
artistsListView = new WeakReference<>(list);
- artistsProvider.requestData();
+
+ subscribe(dbSource.getAllArtists()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::provideData,
+ throwable -> Timber.e("DBError", "Error while reading cached artists")));
+
+ artistsProvider.requestData()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::provideData,
+ e -> Timber.e(e, "takeListView -> requestData"));
}
@Override
@@ -47,6 +70,15 @@ public void takeDetailedView(ArtistInfoView info, Artist artist) {
@Override
public void provideData(List response) {
artistsListView.get().setAdapter(new ArtistsRecyclerAdapter(response, this));
+ dbSource.clearArtists();
+ Completable.fromAction(() -> {
+ Timber.e("Working on: " + Thread.currentThread().getName());
+ for (Artist artist : response) {
+ dbSource.insertArtist(artist);
+ }
+ }).subscribeOn(Schedulers.io()).subscribe();
+
+
}
@Override
diff --git a/app/src/main/java/ru/aleien/yapplication/ListArtistsActivity.java b/app/src/main/java/ru/aleien/yapplication/ListArtistsActivity.java
deleted file mode 100644
index 4c72636..0000000
--- a/app/src/main/java/ru/aleien/yapplication/ListArtistsActivity.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package ru.aleien.yapplication;
-
-import android.os.Bundle;
-import android.os.PersistableBundle;
-import android.support.v4.app.Fragment;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
-
-public class ListArtistsActivity extends AppCompatActivity implements MainView {
- private ArtistsPresenter artistsPresenter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- setupToolbar();
- instantiatePresenter(savedInstanceState);
-
- }
-
- private void instantiatePresenter(Bundle savedInstanceState) {
- if (savedInstanceState != null && savedInstanceState.containsKey("presenterState")) {
- artistsPresenter = (ArtistsPresenter) savedInstanceState.get("presenterState");
- } else {
- artistsPresenter = new ArtistsPresenter(this);
- }
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- artistsPresenter.attachView(this);
- artistsPresenter.onStart();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- artistsPresenter.detachView();
- }
-
- @Override
- public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
- super.onSaveInstanceState(outState, outPersistentState);
- outState.putSerializable("presenterState", artistsPresenter);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- public boolean onOptionsItemSelected(MenuItem menuItem) {
- if (menuItem.getItemId() == android.R.id.home) {
- getSupportActionBar().setDisplayHomeAsUpEnabled(false);
- getSupportFragmentManager().popBackStack();
- }
- return super.onOptionsItemSelected(menuItem);
- }
-
- @SuppressWarnings("ConstantConditions")
- private void setupToolbar() {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
-
- getSupportActionBar().setDisplayShowHomeEnabled(true);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- public void changeFragmentTo(Fragment fragment, boolean hideBackButton) {
- getSupportActionBar().setDisplayHomeAsUpEnabled(hideBackButton);
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.fragment_container, fragment)
- .addToBackStack(null)
- .commit();
- }
-
- @Override
- public void onBackPressed() {
- super.onBackPressed();
- //noinspection ConstantConditions
- getSupportActionBar().setDisplayHomeAsUpEnabled(false);
- }
-}
diff --git a/app/src/main/java/ru/aleien/yapplication/MainActivity.java b/app/src/main/java/ru/aleien/yapplication/MainActivity.java
new file mode 100644
index 0000000..3cb4beb
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/MainActivity.java
@@ -0,0 +1,188 @@
+package ru.aleien.yapplication;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.database.Cursor;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.PersistableBundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import javax.inject.Inject;
+
+import butterknife.BindString;
+import butterknife.ButterKnife;
+import ru.aleien.yapplication.database.DBContract;
+import ru.aleien.yapplication.model.Artist;
+import ru.aleien.yapplication.screens.list.AboutDialogFragment;
+import ru.aleien.yapplication.utils.PendingIntentBuilder;
+import timber.log.Timber;
+
+public class MainActivity extends AppCompatActivity implements MainView {
+ private final static int MUSIC_ID = 1010;
+ private final static int RADIO_ID = 1020;
+
+ private BroadcastReceiver broadcastReceiver;
+ @Inject ArtistsPresenter artistsPresenter;
+
+ @BindString(R.string.about_title) String aboutTitle;
+ @BindString(R.string.about_message) String aboutMessage;
+ @BindString(R.string.title_dismiss) String dismissTitle;
+ @BindString(R.string.email_author) String emailTo;
+ @BindString(R.string.email_title) String emailTitle;
+ private final static Intent EMAIL_INTENT = new Intent(Intent.ACTION_SENDTO)
+ .setType("text/plain")
+ .setData(Uri.parse("mailto:"))
+ .putExtra(Intent.EXTRA_EMAIL, new String[]{"technogenom@gmail.com"})
+ .putExtra(Intent.EXTRA_SUBJECT, "Re: Yapplication");
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ ((App) getApplication()).dagger().inject(this);
+ broadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
+ showHeadphonesNotification(audioManager.isWiredHeadsetOn()
+ || audioManager.isBluetoothA2dpOn()
+ || audioManager.isBluetoothScoOn());
+
+ }
+ };
+
+ setContentView(R.layout.activity_main);
+ ButterKnife.bind(this);
+ setupToolbar();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ artistsPresenter.attachView(this);
+ artistsPresenter.onStart();
+
+ registerReceiver(broadcastReceiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ artistsPresenter.detachView();
+ unregisterReceiver(broadcastReceiver);
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
+ super.onSaveInstanceState(outState, outPersistentState);
+ outState.putSerializable("presenterState", artistsPresenter);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.main_menu, menu);
+ return true;
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ @Override
+ public boolean onOptionsItemSelected(MenuItem menuItem) {
+ switch (menuItem.getItemId()) {
+ case android.R.id.home:
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+ getSupportFragmentManager().popBackStack();
+ break;
+ case R.id.menu_about:
+ showAbout();
+ break;
+ case R.id.menu_contact:
+ composeEmail();
+ break;
+ }
+
+ return super.onOptionsItemSelected(menuItem);
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ private void setupToolbar() {
+ Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ @Override
+ public void changeFragmentTo(Fragment fragment, boolean hideBackButton) {
+ getSupportActionBar().setDisplayHomeAsUpEnabled(hideBackButton);
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragment_container, fragment)
+ .addToBackStack(null)
+ .commit();
+ }
+
+ @Override
+ public void onBackPressed() {
+ super.onBackPressed();
+ //noinspection ConstantConditions
+ getSupportActionBar().setDisplayHomeAsUpEnabled(false);
+ }
+
+ // TODO: Вынести в отдельный класс
+ // TODO: При открытой странице инфо об артисте, открывать страницу артиста
+ private void showHeadphonesNotification(boolean wiredHeadsetOn) {
+
+ PendingIntent musicPendingIntent = PendingIntentBuilder.buildOpenMarketPendingIntent(MUSIC_ID, "ru.yandex.music", this);
+ PendingIntent radioPendingIntent = PendingIntentBuilder.buildOpenMarketPendingIntent(RADIO_ID, "ru.yandex.radio", this);
+
+ int musicNotificationId = 001;
+
+ if (wiredHeadsetOn) {
+ NotificationCompat.Builder musicNotificationBuilder =
+ new NotificationCompat.Builder(this)
+ .setSmallIcon(R.drawable.ic_stat_hardware_headset)
+ .setColor(ContextCompat.getColor(this, R.color.colorPrimary))
+ .setContentTitle("Headphones plugged in")
+ .addAction(R.drawable.ic_stat_yamusic, "Ya.Music", musicPendingIntent)
+ .addAction(R.drawable.ic_stat_hardware_headset, "Ya.Radio", radioPendingIntent)
+ .setContentText("Open in:");
+
+ NotificationManager mNotifyMgr =
+ (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ mNotifyMgr.notify(musicNotificationId, musicNotificationBuilder.build());
+ } else {
+ NotificationManager mNotifyMgr =
+ (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ mNotifyMgr.cancel(musicNotificationId);
+ }
+ }
+
+ private void composeEmail() {
+ if (EMAIL_INTENT.resolveActivity(getPackageManager()) != null) {
+ startActivity(EMAIL_INTENT);
+ }
+ }
+
+ private void showAbout() {
+ DialogFragment aboutFragment = AboutDialogFragment
+ .newInstance(aboutTitle, aboutMessage);
+ aboutFragment.show(getSupportFragmentManager(), "dialog");
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/base/BasePresenter.java b/app/src/main/java/ru/aleien/yapplication/base/BasePresenter.java
index 39c9ab4..e7c685c 100644
--- a/app/src/main/java/ru/aleien/yapplication/base/BasePresenter.java
+++ b/app/src/main/java/ru/aleien/yapplication/base/BasePresenter.java
@@ -2,6 +2,9 @@
import java.lang.ref.WeakReference;
+import rx.Subscription;
+import rx.subscriptions.CompositeSubscription;
+
/**
* Created by aleien on 21.04.16.
* Базовый класс для презентера, отвечает за сохранение ссылки на представление (вьюху).
@@ -9,14 +12,20 @@
*/
public abstract class BasePresenter {
private WeakReference view;
+ private CompositeSubscription subs = new CompositeSubscription();
public abstract void onStart();
+ public void subscribe(Subscription sub) {
+ subs.add(sub);
+ }
+
public void attachView(V view) {
this.view = new WeakReference<>(view);
}
public void detachView() {
+ subs.clear();
view.clear();
view = null;
}
diff --git a/app/src/main/java/ru/aleien/yapplication/contentprovider/ArtistsContentProvider.java b/app/src/main/java/ru/aleien/yapplication/contentprovider/ArtistsContentProvider.java
new file mode 100644
index 0000000..05163b3
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/contentprovider/ArtistsContentProvider.java
@@ -0,0 +1,175 @@
+package ru.aleien.yapplication.contentprovider;
+
+import android.content.ContentProvider;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import ru.aleien.yapplication.database.DBContract;
+import ru.aleien.yapplication.database.DBHelper;
+import timber.log.Timber;
+
+import static ru.aleien.yapplication.contentprovider.ProviderContract.ARTISTS_PATH;
+import static ru.aleien.yapplication.contentprovider.ProviderContract.AUTHORITY;
+import static ru.aleien.yapplication.contentprovider.ProviderContract.URI_ARTISTS;
+import static ru.aleien.yapplication.contentprovider.ProviderContract.URI_ARTISTS_ID;
+
+public class ArtistsContentProvider extends ContentProvider {
+
+ private static final UriMatcher uriMatcher;
+
+ static {
+ uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ uriMatcher.addURI(AUTHORITY, ARTISTS_PATH, URI_ARTISTS);
+ uriMatcher.addURI(AUTHORITY, ARTISTS_PATH + "/#", URI_ARTISTS_ID);
+ }
+
+ DBHelper dbHelper;
+ SQLiteDatabase db;
+
+ @Override
+ public boolean onCreate() {
+ Timber.d("Content provider created");
+ dbHelper = new DBHelper(getContext());
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
+ Timber.v("Making query to content provider");
+ Timber.d("Uri: " + uri.toString());
+ switch (uriMatcher.match(uri)) {
+ case URI_ARTISTS:
+ Timber.v("Resolving query to ARTISTS");
+ break;
+ case URI_ARTISTS_ID:
+ Timber.v("Resolving query to specific ARTIST");
+ String id = uri.getLastPathSegment();
+
+ if (TextUtils.isEmpty(selection)) {
+ selection = DBContract.Artists.ID + " = " + id;
+ } else {
+ selection = selection + " AND " + DBContract.Artists.ID + " = " + id;
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Wrong URI: " + uri);
+ }
+
+ db = dbHelper.getReadableDatabase();
+ return db.query(DBContract.Artists.TABLE,
+ projection, selection, selectionArgs, null, null, sortOrder);
+ }
+
+ @Nullable
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ if (uriMatcher.match(uri) != ProviderContract.URI_ARTISTS) {
+ throw new IllegalArgumentException(
+ "Unsupported URI for insertion: " + uri);
+ }
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ if (uriMatcher.match(uri) == URI_ARTISTS) {
+ long id = db.insert(
+ DBContract.Artists.TABLE,
+ null,
+ values);
+ return getUriForId(id, uri);
+ }
+
+ return null;
+ }
+
+ private Uri getUriForId(long id, Uri uri) {
+ if (id > 0) {
+ Uri itemUri = ContentUris.withAppendedId(uri, id);
+ ContentResolver resolver = getContext() == null ? null : getContext().getContentResolver();
+ if (resolver != null) {
+ getContext().getContentResolver()
+ .notifyChange(itemUri, null);
+ }
+
+ return itemUri;
+ }
+ throw new SQLException(
+ "Problem while inserting into uri: " + uri);
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ int delCount = 0;
+ switch (uriMatcher.match(uri)) {
+ case URI_ARTISTS:
+ delCount = db.delete(
+ DBContract.Artists.TABLE,
+ selection,
+ selectionArgs);
+ break;
+ case URI_ARTISTS_ID:
+ String idStr = uri.getLastPathSegment();
+ String where = DBContract.Artists.ID + " = " + idStr;
+ if (!TextUtils.isEmpty(selection)) {
+ where += " AND " + selection;
+ }
+ delCount = db.delete(
+ DBContract.Artists.TABLE,
+ where,
+ selectionArgs);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported URI: " + uri);
+ }
+ if (delCount > 0) {
+ getContext().getContentResolver().notifyChange(uri, null);
+ }
+ return delCount;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ SQLiteDatabase db = dbHelper.getWritableDatabase();
+ int updateCount = 0;
+ switch (uriMatcher.match(uri)) {
+ case URI_ARTISTS:
+ updateCount = db.update(
+ DBContract.Artists.TABLE,
+ values,
+ selection,
+ selectionArgs);
+ break;
+ case URI_ARTISTS_ID:
+ String idStr = uri.getLastPathSegment();
+ String where = DBContract.Artists.ID + " = " + idStr;
+ if (!TextUtils.isEmpty(selection)) {
+ where += " AND " + selection;
+ }
+ updateCount = db.update(
+ DBContract.Artists.TABLE,
+ values,
+ where,
+ selectionArgs);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported URI: " + uri);
+ }
+ if (updateCount > 0) {
+ getContext().getContentResolver().notifyChange(uri, null);
+ }
+ return updateCount;
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/contentprovider/ProviderContract.java b/app/src/main/java/ru/aleien/yapplication/contentprovider/ProviderContract.java
new file mode 100644
index 0000000..490a65d
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/contentprovider/ProviderContract.java
@@ -0,0 +1,16 @@
+package ru.aleien.yapplication.contentprovider;
+
+/**
+ * Created by aleien on 12.08.16.
+ * Контракт поставщика контента
+ */
+
+public final class ProviderContract {
+
+ public static final String AUTHORITY = "ru.aleien.yapplication.provider";
+
+ public static final String ARTISTS_PATH = "Artists";
+ public static final int URI_ARTISTS = 1;
+ public static final int URI_ARTISTS_ID = 2;
+
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/database/DBBackend.java b/app/src/main/java/ru/aleien/yapplication/database/DBBackend.java
new file mode 100644
index 0000000..95064e4
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/database/DBBackend.java
@@ -0,0 +1,134 @@
+package ru.aleien.yapplication.database;
+
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import ru.aleien.yapplication.model.Artist;
+import rx.Observable;
+
+import static ru.aleien.yapplication.database.DBContract.GenreToArtist.ARTIST_ID;
+import static ru.aleien.yapplication.database.DBContract.GenreToArtist.GENRE_ID;
+import static ru.aleien.yapplication.database.DBContract.GenreToArtist.TABLE;
+import static ru.aleien.yapplication.database.DBContract.allColumns;
+
+public class DBBackend {
+
+ private DBHelper dbOpenHelper;
+
+ @Inject
+ public DBBackend(DBHelper helper) {
+ dbOpenHelper = helper;
+ }
+
+ public void insertArtist(Artist artist) {
+ insertArtist(artist.id,
+ artist.name,
+ artist.tracks,
+ artist.albums,
+ artist.link,
+ artist.description,
+ artist.cover.small,
+ artist.cover.big,
+ artist.genres);
+ }
+
+ void insertArtist(int id,
+ String name,
+ int tracks,
+ int albums,
+ String link,
+ String description,
+ String small_cover,
+ String big_cover,
+ List genres) {
+ SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
+ db.beginTransaction();
+
+ try {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(DBContract.Artists.ID, id);
+ contentValues.put(DBContract.Artists.NAME, name);
+ contentValues.put(DBContract.Artists.TRACKS, tracks);
+ contentValues.put(DBContract.Artists.ALBUMS, albums);
+ contentValues.put(DBContract.Artists.LINK, link);
+ contentValues.put(DBContract.Artists.DESCRIPTION, description);
+ contentValues.put(DBContract.Artists.SMALL_COVER, small_cover);
+ contentValues.put(DBContract.Artists.BIG_COVER, big_cover);
+
+ long artistId = db.insert(DBContract.Artists.TABLE, null, contentValues);
+ List genresIds = insertGenres(genres);
+
+ insertRelation(artistId, genresIds);
+
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ void insertRelation(long artistId, List genresIds) {
+ SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
+ for (Long genreId : genresIds) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(ARTIST_ID, artistId);
+ contentValues.put(GENRE_ID, genreId);
+ db.insert(TABLE, null, contentValues);
+ }
+ }
+
+ List insertGenres(List genres) {
+ SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
+ List rowIds = new ArrayList<>();
+ ContentValues contentValues = new ContentValues();
+ for (String genre : genres) {
+ contentValues.put(DBContract.Genres.NAME, genre);
+ long rowId = db.insertWithOnConflict(DBContract.Genres.TABLE, null, contentValues, SQLiteDatabase.CONFLICT_IGNORE);
+ rowIds.add(rowId);
+ }
+
+ return rowIds;
+ }
+
+ public Observable> getAllArtists() {
+ return Observable.fromCallable(this::loadArtists);
+ }
+
+ List loadArtists() {
+ List artists = new ArrayList<>();
+ SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
+ Cursor cursor = db.query(DBContract.Artists.TABLE,
+ allColumns, null, null, null, null, null);
+ cursor.moveToFirst();
+
+ while (!cursor.isAfterLast()) {
+ artists.add(cursorToArtist(cursor));
+ cursor.moveToNext();
+ }
+
+ cursor.close();
+
+ return artists;
+ }
+
+ public void clearArtists() {
+ dbOpenHelper.getWritableDatabase().execSQL("DELETE FROM " + DBContract.Artists.TABLE);
+ }
+
+ private Artist cursorToArtist(Cursor cursor) {
+ return new Artist(cursor.getInt(cursor.getColumnIndex(DBContract.Artists.ID)),
+ cursor.getString(cursor.getColumnIndex(DBContract.Artists.NAME)),
+ new ArrayList<>(),
+ cursor.getInt(cursor.getColumnIndex(DBContract.Artists.TRACKS)),
+ cursor.getInt(cursor.getColumnIndex(DBContract.Artists.ALBUMS)),
+ cursor.getString(cursor.getColumnIndex(DBContract.Artists.LINK)),
+ cursor.getString(cursor.getColumnIndex(DBContract.Artists.DESCRIPTION)),
+ new Artist.Cover(cursor.getString(cursor.getColumnIndex(DBContract.Artists.SMALL_COVER)),
+ cursor.getString(cursor.getColumnIndex(DBContract.Artists.BIG_COVER))));
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/database/DBContract.java b/app/src/main/java/ru/aleien/yapplication/database/DBContract.java
new file mode 100644
index 0000000..01fdc3c
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/database/DBContract.java
@@ -0,0 +1,48 @@
+package ru.aleien.yapplication.database;
+
+/**
+ * Created by aleien on 08.08.16.
+ * Класс для хранения и структурирования полей в базе данных
+ */
+
+public interface DBContract {
+ String DBNAME = "ArtistsDB";
+ int DB_VERSION = 1;
+
+ interface Artists {
+ String TABLE = "artists";
+ String ID = "id";
+ String NAME = "name";
+ String TRACKS = "tracks";
+ String ALBUMS = "albums";
+ String LINK = "link";
+ String DESCRIPTION = "description";
+ String SMALL_COVER = "small_cover";
+ String BIG_COVER = "big_cover";
+ }
+
+ interface Genres {
+ String TABLE = "genres";
+ String NAME = "genre";
+ }
+
+ // А может быть тут можно не genre_id, а genre_name?
+ interface GenreToArtist {
+ String TABLE = "genre_to_artist";
+ String ARTIST_ID = "artist_id";
+ String GENRE_ID = "genre_id";
+ }
+
+ String DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS ";
+
+ String[] allColumns = new String[]{
+ Artists.ID,
+ Artists.NAME,
+ Artists.TRACKS,
+ Artists.ALBUMS,
+ Artists.LINK,
+ Artists.DESCRIPTION,
+ Artists.SMALL_COVER,
+ Artists.BIG_COVER
+ };
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/database/DBHelper.java b/app/src/main/java/ru/aleien/yapplication/database/DBHelper.java
new file mode 100644
index 0000000..cef9051
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/database/DBHelper.java
@@ -0,0 +1,61 @@
+package ru.aleien.yapplication.database;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import ru.aleien.yapplication.model.Artist;
+
+import static ru.aleien.yapplication.database.DBContract.DB_VERSION;
+import static ru.aleien.yapplication.database.DBContract.DROP_TABLE_IF_EXISTS;
+
+@Singleton
+public class DBHelper extends SQLiteOpenHelper {
+
+ @Inject
+ public DBHelper(Context context) {
+ super(context, DBContract.DBNAME, null, DB_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(
+ "CREATE TABLE " + DBContract.Artists.TABLE +
+ "(" +
+ DBContract.Artists.ID + " INTEGER PRIMARY KEY, " +
+ DBContract.Artists.NAME + " TEXT NOT NULL," +
+ DBContract.Artists.TRACKS + " INTEGER," +
+ DBContract.Artists.ALBUMS + " INTEGER," +
+ DBContract.Artists.LINK + " TEXT," +
+ DBContract.Artists.DESCRIPTION + " TEXT," +
+ DBContract.Artists.SMALL_COVER + " TEXT," +
+ DBContract.Artists.BIG_COVER + " TEXT" +
+ ")"
+ );
+
+ db.execSQL(
+ "CREATE TABLE " +
+ DBContract.Genres.TABLE +
+ " (" +
+ DBContract.Genres.NAME + " TEXT UNIQUE NOT NULL" +
+ ")");
+
+ db.execSQL(
+ "CREATE TABLE " + DBContract.GenreToArtist.TABLE +
+ " (" +
+ DBContract.GenreToArtist.ARTIST_ID + " INTEGER NOT NULL," +
+ DBContract.GenreToArtist.GENRE_ID + " INTEGER NOT NULL)");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int i, int i1) {
+ db.execSQL(DROP_TABLE_IF_EXISTS + DBContract.Artists.TABLE);
+ db.execSQL(DROP_TABLE_IF_EXISTS + DBContract.Genres.TABLE);
+ db.execSQL(DROP_TABLE_IF_EXISTS + DBContract.GenreToArtist.TABLE);
+ onCreate(db);
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/database/DBProvider.java b/app/src/main/java/ru/aleien/yapplication/database/DBProvider.java
new file mode 100644
index 0000000..b03b6e8
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/database/DBProvider.java
@@ -0,0 +1,9 @@
+package ru.aleien.yapplication.database;
+
+/**
+ * Created by aleien on 10.08.16.
+ */
+
+public class DBProvider {
+
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/dataprovider/ArtistsProvider.java b/app/src/main/java/ru/aleien/yapplication/dataprovider/ArtistsProvider.java
index 901e925..a9854fc 100644
--- a/app/src/main/java/ru/aleien/yapplication/dataprovider/ArtistsProvider.java
+++ b/app/src/main/java/ru/aleien/yapplication/dataprovider/ArtistsProvider.java
@@ -1,9 +1,15 @@
package ru.aleien.yapplication.dataprovider;
+import java.util.List;
+
+import ru.aleien.yapplication.model.Artist;
+import rx.Observable;
+
/**
* Created by aleien on 09.04.16.
* Интерфейс между контроллером и поставщиком данных
*/
public interface ArtistsProvider {
- void requestData();
+ // Лучше дженерик?
+ Observable> requestData();
}
diff --git a/app/src/main/java/ru/aleien/yapplication/dataprovider/WebArtistsProvider.java b/app/src/main/java/ru/aleien/yapplication/dataprovider/WebArtistsProvider.java
index 962b84f..720db16 100644
--- a/app/src/main/java/ru/aleien/yapplication/dataprovider/WebArtistsProvider.java
+++ b/app/src/main/java/ru/aleien/yapplication/dataprovider/WebArtistsProvider.java
@@ -1,23 +1,12 @@
package ru.aleien.yapplication.dataprovider;
-import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-
-import java.io.IOException;
import java.util.List;
-import okhttp3.Cache;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.Interceptor;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import ru.aleien.yapplication.ArtistsRequester;
+import javax.inject.Inject;
+
+import ru.aleien.yapplication.di.AppModule;
import ru.aleien.yapplication.model.Artist;
-import ru.aleien.yapplication.utils.Utils;
+import rx.Observable;
/**
* Created by aleien on 09.04.16.
@@ -25,40 +14,17 @@
*/
public class WebArtistsProvider implements ArtistsProvider {
- private static final String JSON_URL = "http://cache-default03g.cdn.yandex.net/download.cdn.yandex.net/mobilization-2016/artists.json";
- private final ArtistsRequester artistsRequester;
- private OkHttpClient client;
- public WebArtistsProvider(ArtistsRequester artistsRequester, Context context) {
- this.artistsRequester = artistsRequester;
- Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = Utils.createInterceptor(context);
- Cache cache = Utils.getCache(context);
- client = new OkHttpClient.Builder()
- .cache(cache)
- .addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
- .build();
+ private AppModule.Api api;
+
+ @Inject
+ public WebArtistsProvider(AppModule.Api api) {
+ this.api = api;
}
@Override
- public void requestData() {
- Handler mainHandler = new Handler(Looper.getMainLooper());
- Request request = new Request.Builder()
- .url(JSON_URL)
- .build();
-
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- Log.d("Main", "FAIL");
- }
-
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- List responseList = Utils.decodeResponse(response);
- mainHandler.post(() -> artistsRequester.provideData(responseList)); // Очень странно, что onResponse выполняется не в main-треде
- // Вместо хэндлера можно, например, использовать rx-яву, которая очень хорошо дружит с ретрофитом
- }
- });
+ public Observable> requestData() {
+ return api.getArtists();
}
}
diff --git a/app/src/main/java/ru/aleien/yapplication/di/AppComponent.java b/app/src/main/java/ru/aleien/yapplication/di/AppComponent.java
new file mode 100644
index 0000000..6a7ab21
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/di/AppComponent.java
@@ -0,0 +1,14 @@
+package ru.aleien.yapplication.di;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+import ru.aleien.yapplication.MainActivity;
+
+@Singleton
+@Component(modules = AppModule.class)
+public interface AppComponent {
+
+ void inject(MainActivity mainActivity);
+
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/di/AppModule.java b/app/src/main/java/ru/aleien/yapplication/di/AppModule.java
new file mode 100644
index 0000000..d0a7119
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/di/AppModule.java
@@ -0,0 +1,76 @@
+package ru.aleien.yapplication.di;
+
+import android.app.Application;
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+
+import java.util.List;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import dagger.Module;
+import dagger.Provides;
+import okhttp3.OkHttpClient;
+import okhttp3.logging.HttpLoggingInterceptor;
+import retrofit2.Retrofit;
+import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
+import retrofit2.converter.gson.GsonConverterFactory;
+import retrofit2.http.GET;
+import ru.aleien.yapplication.database.DBContract;
+import ru.aleien.yapplication.model.Artist;
+import rx.Observable;
+
+import static android.content.Context.MODE_PRIVATE;
+
+@Module
+public class AppModule {
+ private static final String BASE_URL = "http://cache-default03g.cdn.yandex.net/download.cdn.yandex.net/mobilization-2016/";
+
+ private Context context;
+
+ public AppModule(Application application) {
+ this.context = application;
+ }
+
+ @Provides
+ @Singleton
+ Context provideContext() {
+ return this.context;
+ }
+
+ @Provides
+ @Singleton
+ SQLiteDatabase provideDatabase(Context context) {
+ return context.openOrCreateDatabase(DBContract.DBNAME, MODE_PRIVATE, null);
+ }
+
+ @Provides
+ @Singleton
+ Retrofit provideRestClient(OkHttpClient client) {
+ return new Retrofit.Builder()
+ .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create())
+ .baseUrl(BASE_URL)
+ .client(client)
+ .build();
+ }
+
+ @Provides
+ @Singleton
+ OkHttpClient provideOkhttpClient() {
+ return new OkHttpClient.Builder()
+ .addInterceptor(new HttpLoggingInterceptor())
+ .build();
+ }
+
+ @Provides
+ Api provideApi(Retrofit rest) {
+ return rest.create(Api.class);
+ }
+
+ public interface Api {
+ @GET("artists.json")
+ Observable> getArtists();
+ }
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/model/Artist.java b/app/src/main/java/ru/aleien/yapplication/model/Artist.java
index b9d39de..66a5a24 100644
--- a/app/src/main/java/ru/aleien/yapplication/model/Artist.java
+++ b/app/src/main/java/ru/aleien/yapplication/model/Artist.java
@@ -23,6 +23,36 @@ public Artist(int id, String name, List genres, int tracks, int albums,
this.cover = cover;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Artist artist = (Artist) o;
+
+ if (id != artist.id) return false;
+ if (tracks != artist.tracks) return false;
+ if (albums != artist.albums) return false;
+ if (!name.equals(artist.name)) return false;
+ if (!genres.equals(artist.genres)) return false;
+ if (!link.equals(artist.link)) return false;
+ if (!description.equals(artist.description)) return false;
+ return cover.equals(artist.cover);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = id;
+ result = 31 * result + name.hashCode();
+ result = 31 * result + genres.hashCode();
+ result = 31 * result + tracks;
+ result = 31 * result + albums;
+ result = 31 * result + link.hashCode();
+ result = 31 * result + description.hashCode();
+ result = 31 * result + cover.hashCode();
+ return result;
+ }
+
public static class Cover {
public final String small;
public final String big;
@@ -31,6 +61,25 @@ public Cover(String small, String big) {
this.small = small;
this.big = big;
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ Cover cover = (Cover) o;
+
+ if (!small.equals(cover.small)) return false;
+ return big.equals(cover.big);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = small.hashCode();
+ result = 31 * result + big.hashCode();
+ return result;
+ }
}
}
diff --git a/app/src/main/java/ru/aleien/yapplication/screens/detailedinfo/ArtistInfoFragment.java b/app/src/main/java/ru/aleien/yapplication/screens/detailedinfo/ArtistInfoFragment.java
index 90019a1..ecf63b1 100644
--- a/app/src/main/java/ru/aleien/yapplication/screens/detailedinfo/ArtistInfoFragment.java
+++ b/app/src/main/java/ru/aleien/yapplication/screens/detailedinfo/ArtistInfoFragment.java
@@ -12,7 +12,7 @@
import java.util.Locale;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import ru.aleien.yapplication.R;
import ru.aleien.yapplication.model.Artist;
@@ -25,13 +25,13 @@
* Фрагмент для отображения информации о музыканте.
*/
public class ArtistInfoFragment extends Fragment implements ArtistInfoView {
- @Bind(R.id.info_cover)
+ @BindView(R.id.info_cover)
ImageView cover;
- @Bind(R.id.info_genres)
+ @BindView(R.id.info_genres)
TextView genres;
- @Bind(R.id.info_music)
+ @BindView(R.id.info_music)
TextView infoMusic;
- @Bind(R.id.info_bio)
+ @BindView(R.id.info_bio)
TextView bio;
private Artist artist;
diff --git a/app/src/main/java/ru/aleien/yapplication/screens/list/AboutDialogFragment.java b/app/src/main/java/ru/aleien/yapplication/screens/list/AboutDialogFragment.java
new file mode 100644
index 0000000..270ad35
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/screens/list/AboutDialogFragment.java
@@ -0,0 +1,34 @@
+package ru.aleien.yapplication.screens.list;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+
+import ru.aleien.yapplication.R;
+
+public class AboutDialogFragment extends DialogFragment {
+
+ public static AboutDialogFragment newInstance(String title, String message) {
+ AboutDialogFragment frag = new AboutDialogFragment();
+ Bundle args = new Bundle();
+ args.putString("title", title);
+ args.putString("message", message);
+ frag.setArguments(args);
+ return frag;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ String title = getArguments().getString("title");
+ String message = getArguments().getString("message");
+
+ return new AlertDialog.Builder(getActivity())
+ .setTitle(title)
+ .setMessage(message)
+ .setPositiveButton(R.string.alert_dialog_ok,
+ (dialog, whichButton) -> dismiss()
+ )
+ .create();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/aleien/yapplication/screens/list/ArtistsRecyclerFragment.java b/app/src/main/java/ru/aleien/yapplication/screens/list/ArtistsRecyclerFragment.java
index d7a3a77..cfc2a05 100644
--- a/app/src/main/java/ru/aleien/yapplication/screens/list/ArtistsRecyclerFragment.java
+++ b/app/src/main/java/ru/aleien/yapplication/screens/list/ArtistsRecyclerFragment.java
@@ -9,8 +9,9 @@
import android.view.View;
import android.view.ViewGroup;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
+import butterknife.Unbinder;
import ru.aleien.yapplication.R;
import ru.aleien.yapplication.utils.adapters.ArtistsRecyclerAdapter;
@@ -19,23 +20,30 @@
* Фрагмент для отображения списка музыкантов.
*/
public class ArtistsRecyclerFragment extends Fragment implements ArtistsListView {
- @Bind(R.id.artists_list)
+ @BindView(R.id.artists_list)
RecyclerView artistsRecycler;
private ArtistsRecyclerAdapter adapter;
+ private Unbinder unbinder;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View fragmentView = inflater.inflate(R.layout.fragment_artists_recycler, container, false);
- ButterKnife.bind(this, fragmentView);
+ unbinder = ButterKnife.bind(this, fragmentView);
return fragmentView;
}
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ unbinder.unbind();
+ }
+
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- artistsRecycler.setLayoutManager(new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));
+ artistsRecycler.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
artistsRecycler.setAdapter(adapter);
artistsRecycler.setHasFixedSize(true);
}
diff --git a/app/src/main/java/ru/aleien/yapplication/utils/PendingIntentBuilder.java b/app/src/main/java/ru/aleien/yapplication/utils/PendingIntentBuilder.java
new file mode 100644
index 0000000..04075e1
--- /dev/null
+++ b/app/src/main/java/ru/aleien/yapplication/utils/PendingIntentBuilder.java
@@ -0,0 +1,42 @@
+package ru.aleien.yapplication.utils;
+
+import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+
+/**
+ * Created by user on 19.07.16.
+ */
+public class PendingIntentBuilder {
+ private static final String playStore = "market://details?id=";
+
+ public static PendingIntent buildOpenMarketPendingIntent(int id, String pack, Context context) {
+ Intent intent = buildOpenAppOrMarketPageIntent(pack, context);
+ return PendingIntent.getActivity(context, id, intent, 0);
+ }
+
+ public static Intent buildOpenAppOrMarketPageIntent(String pack, Context context) {
+
+ try {
+ if (Utils.checkPackageExists(context, pack)) {
+ PackageManager pm = context.getPackageManager();
+ return pm.getLaunchIntentForPackage(pack);
+ } else {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(playStore + pack));
+ return intent;
+ }
+ } catch (ActivityNotFoundException e) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(playStore + pack));
+ return intent;
+ }
+
+ }
+
+
+
+}
diff --git a/app/src/main/java/ru/aleien/yapplication/utils/Utils.java b/app/src/main/java/ru/aleien/yapplication/utils/Utils.java
index 6b5c718..b46b6ce 100644
--- a/app/src/main/java/ru/aleien/yapplication/utils/Utils.java
+++ b/app/src/main/java/ru/aleien/yapplication/utils/Utils.java
@@ -1,22 +1,11 @@
package ru.aleien.yapplication.utils;
import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.support.annotation.NonNull;
+import android.content.pm.PackageManager;
-import com.google.gson.Gson;
-import com.google.gson.reflect.TypeToken;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.reflect.Type;
import java.util.List;
-import okhttp3.Cache;
-import okhttp3.Interceptor;
-import okhttp3.Response;
-import ru.aleien.yapplication.model.Artist;
+import timber.log.Timber;
public class Utils {
@@ -33,49 +22,25 @@ public static String convertToString(List list, Character separator) {
return resultString.toString();
}
- public static boolean isNetworkAvailable(Context context) {
- ConnectivityManager connectivityManager = (ConnectivityManager) context.getApplicationContext()
- .getSystemService(Context.CONNECTIVITY_SERVICE);
-
- NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
- return (activeNetworkInfo != null) && (activeNetworkInfo.isConnected());
- }
-
- @NonNull
- public static Interceptor createInterceptor(Context context) {
- return chain -> {
- Response originalResponse = chain.proceed(chain.request());
- if (Utils.isNetworkAvailable(context)) {
- int maxAge = 60;
- return originalResponse.newBuilder()
- .header("Cache-Control", "public, max-age=" + maxAge)
- .build();
- } else {
- int maxStale = 60 * 60 * 24 * 28;
- return originalResponse.newBuilder()
- .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
- .build();
- }
- };
- }
+ public static String getAppVersion(Context context) {
+ String versionCode = "1.0";
+ try {
+ versionCode = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ Timber.e(e, "getAppVersion: Could not get package info");
+ e.printStackTrace();
+ }
- public static Cache getCache(Context context) {
- File httpCacheDirectory = new File(context.getCacheDir(), "responses");
- int cacheSize = 10 * 1024 * 1024; // 10 MiB
- return new Cache(httpCacheDirectory, cacheSize);
+ return versionCode;
}
- public static List decodeResponse(Response response) {
- List resultList = null;
- Type listType = new TypeToken>() {
- }.getType();
+ public static boolean checkPackageExists(Context context, String targetPackage) {
try {
- resultList = new Gson().fromJson(response.body().string(), listType);
- } catch (IOException e) {
- e.printStackTrace();
+ context.getPackageManager().getPackageInfo(targetPackage, PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
}
-
- return resultList;
+ return true;
}
diff --git a/app/src/main/java/ru/aleien/yapplication/utils/adapters/ArtistsRecyclerAdapter.java b/app/src/main/java/ru/aleien/yapplication/utils/adapters/ArtistsRecyclerAdapter.java
index e291a57..b9172ec 100644
--- a/app/src/main/java/ru/aleien/yapplication/utils/adapters/ArtistsRecyclerAdapter.java
+++ b/app/src/main/java/ru/aleien/yapplication/utils/adapters/ArtistsRecyclerAdapter.java
@@ -12,7 +12,7 @@
import java.util.List;
import java.util.Locale;
-import butterknife.Bind;
+import butterknife.BindView;
import butterknife.ButterKnife;
import ru.aleien.yapplication.ArtistClickHandler;
import ru.aleien.yapplication.R;
@@ -59,15 +59,15 @@ public int getItemCount() {
}
static class ArtistHolder extends RecyclerView.ViewHolder {
- @Bind(R.id.item_container)
+ @BindView(R.id.item_container)
RelativeLayout container;
- @Bind(R.id.cover)
+ @BindView(R.id.cover)
ImageView cover;
- @Bind(R.id.name)
+ @BindView(R.id.name)
TextView name;
- @Bind(R.id.genres)
+ @BindView(R.id.genres)
TextView genres;
- @Bind(R.id.music_info)
+ @BindView(R.id.music_info)
TextView musicInfo;
public ArtistHolder(View itemView) {
diff --git a/app/src/main/res/drawable-hdpi-v11/ic_stat_hardware_headset.png b/app/src/main/res/drawable-hdpi-v11/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..c9507cf
Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-hdpi-v11/ic_stat_yamusic.png b/app/src/main/res/drawable-hdpi-v11/ic_stat_yamusic.png
new file mode 100755
index 0000000..95c6e2f
Binary files /dev/null and b/app/src/main/res/drawable-hdpi-v11/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_hardware_headset.png b/app/src/main/res/drawable-hdpi/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..6b70e37
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_yamusic.png b/app/src/main/res/drawable-hdpi/ic_stat_yamusic.png
new file mode 100755
index 0000000..19c7e81
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_yamusic.png b/app/src/main/res/drawable-hdpi/ic_yamusic.png
new file mode 100755
index 0000000..ea3eeda
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_yamusic.png differ
diff --git a/app/src/main/res/drawable-mdpi-v11/ic_stat_hardware_headset.png b/app/src/main/res/drawable-mdpi-v11/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..c4a65a8
Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-mdpi-v11/ic_stat_yamusic.png b/app/src/main/res/drawable-mdpi-v11/ic_stat_yamusic.png
new file mode 100755
index 0000000..28d132b
Binary files /dev/null and b/app/src/main/res/drawable-mdpi-v11/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_hardware_headset.png b/app/src/main/res/drawable-mdpi/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..deb07a4
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_yamusic.png b/app/src/main/res/drawable-mdpi/ic_stat_yamusic.png
new file mode 100755
index 0000000..7870732
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_yamusic.png b/app/src/main/res/drawable-mdpi/ic_yamusic.png
new file mode 100755
index 0000000..b06a63a
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_yamusic.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_yaradio.png b/app/src/main/res/drawable-mdpi/ic_yaradio.png
new file mode 100755
index 0000000..cec8db2
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_yaradio.png differ
diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xhdpi-v11/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..dae527f
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xhdpi-v11/ic_stat_yamusic.png b/app/src/main/res/drawable-xhdpi-v11/ic_stat_yamusic.png
new file mode 100755
index 0000000..701c0d1
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi-v11/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xhdpi/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..176946e
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_yamusic.png b/app/src/main/res/drawable-xhdpi/ic_stat_yamusic.png
new file mode 100755
index 0000000..6ae61a8
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_yamusic.png b/app/src/main/res/drawable-xhdpi/ic_yamusic.png
new file mode 100755
index 0000000..4a906d4
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_yamusic.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_yaradio.png b/app/src/main/res/drawable-xhdpi/ic_yaradio.png
new file mode 100755
index 0000000..83956e2
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_yaradio.png differ
diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xxhdpi-v11/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..b919e7f
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xxhdpi-v11/ic_stat_yamusic.png b/app/src/main/res/drawable-xxhdpi-v11/ic_stat_yamusic.png
new file mode 100755
index 0000000..f6a8d6c
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi-v11/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xxhdpi/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..296a767
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_stat_yamusic.png b/app/src/main/res/drawable-xxhdpi/ic_stat_yamusic.png
new file mode 100755
index 0000000..108b35e
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_yamusic.png b/app/src/main/res/drawable-xxhdpi/ic_yamusic.png
new file mode 100755
index 0000000..e67d93b
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_yaradio.png b/app/src/main/res/drawable-xxhdpi/ic_yaradio.png
new file mode 100755
index 0000000..928db32
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_yaradio.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..84bf4ef
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_yamusic.png b/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_yamusic.png
new file mode 100755
index 0000000..6cdb8b8
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi-v11/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_stat_hardware_headset.png b/app/src/main/res/drawable-xxxhdpi/ic_stat_hardware_headset.png
new file mode 100755
index 0000000..44e371e
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_stat_hardware_headset.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_stat_yamusic.png b/app/src/main/res/drawable-xxxhdpi/ic_stat_yamusic.png
new file mode 100755
index 0000000..a44264b
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_stat_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_yamusic.png b/app/src/main/res/drawable-xxxhdpi/ic_yamusic.png
new file mode 100755
index 0000000..87be3f0
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_yamusic.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_yaradio.png b/app/src/main/res/drawable-xxxhdpi/ic_yaradio.png
new file mode 100755
index 0000000..958eb25
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_yaradio.png differ
diff --git a/app/src/main/res/drawable/shadow.xml b/app/src/main/res/drawable/shadow.xml
new file mode 100644
index 0000000..4567863
--- /dev/null
+++ b/app/src/main/res/drawable/shadow.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ 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 48e82b4..f8e0c7f 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,24 +1,35 @@
-
+
-
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+
+
+
+
+
-
+ android:layout_height="match_parent"
+ android:layout_marginTop="@dimen/toolbar"/>
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml
new file mode 100644
index 0000000..0f2126c
--- /dev/null
+++ b/app/src/main/res/menu/main_menu.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index adca2aa..7ab8dc7 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -4,4 +4,9 @@
Биография
%d альбомов · %d песен
%d альбомов, %d песен
+ О программе
+ Контакты
+ Простое приложение с простыми потребностями. Никаких проблем.\nНу разве что несмного.
+ О программе
+ ЗАКРЫТЬ
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index fb3aa08..8a8146c 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,8 +1,8 @@
- #6945b6
- #44218b
- #1ff4e6
+ #e74c3c
+ #c0392b
+ #3498db
#000000
#ffffff
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 7e7ae64..612dd69 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -4,4 +4,5 @@
8dp
3dp
100dp
+ 55dp
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 587c55f..e6724ee 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -4,5 +4,16 @@
Biography
%d albums · %d songs
%d albums, %d songs
+ About
+ Contact
+
+ About
+ This is a simple application with simple needs. No worries, no trouble.\n Well, maybe just some.
+ DISMISS
+ technogenom@gmail.com
+ Re: Yapplication
+ OK
+ CANCEL
+
diff --git a/app/src/test/java/ru/aleien/yapplication/ArtistsPresenterTest.java b/app/src/test/java/ru/aleien/yapplication/ArtistsPresenterTest.java
index f73e8c1..0e707f4 100644
--- a/app/src/test/java/ru/aleien/yapplication/ArtistsPresenterTest.java
+++ b/app/src/test/java/ru/aleien/yapplication/ArtistsPresenterTest.java
@@ -7,45 +7,53 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
+import ru.aleien.yapplication.database.DBBackend;
+import ru.aleien.yapplication.database.DBHelper;
import ru.aleien.yapplication.dataprovider.ArtistsProvider;
+import ru.aleien.yapplication.dataprovider.WebArtistsProvider;
import ru.aleien.yapplication.model.Artist;
import ru.aleien.yapplication.screens.detailedinfo.ArtistInfoFragment;
import ru.aleien.yapplication.screens.detailedinfo.ArtistInfoView;
import ru.aleien.yapplication.screens.list.ArtistsListView;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+
/**
* Created by aleien on 09.04.16.
* Тесты!.
*/
-@RunWith(org.robolectric.RobolectricGradleTestRunner.class)
+@RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class ArtistsPresenterTest {
ArtistsPresenter presenter;
@Mock Context context;
@Mock ArtistsProvider provider;
+ @Mock
+ WebArtistsProvider webArtistsProvider;
@Mock Artist artistMock;
@Mock MainView mainMock;
@Mock ArtistsListView listMock;
@Mock ArtistInfoView infoMock;
-
+ @Mock
+ DBBackend dbBackend;
+ @Mock
+ DBHelper dbHelper;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- presenter = new ArtistsPresenter(context);
+ presenter = new ArtistsPresenter(dbBackend, webArtistsProvider);
presenter.artistsProvider = provider;
presenter.attachView(mainMock);
@@ -58,7 +66,6 @@ public void setup() {
})).when(provider).requestData();
}
-
@Test
public void requestData() {
presenter.takeListView(listMock);
@@ -77,7 +84,4 @@ public void artistClicked() {
verify(mainMock, times(1)).changeFragmentTo(any(ArtistInfoFragment.class), anyBoolean());
}
-
-
-
}
diff --git a/app/src/test/java/ru/aleien/yapplication/UtilsTest.java b/app/src/test/java/ru/aleien/yapplication/UtilsTest.java
index f49c172..0998579 100644
--- a/app/src/test/java/ru/aleien/yapplication/UtilsTest.java
+++ b/app/src/test/java/ru/aleien/yapplication/UtilsTest.java
@@ -13,7 +13,7 @@
import static junit.framework.Assert.assertEquals;
-@RunWith(org.robolectric.RobolectricGradleTestRunner.class)
+@RunWith(org.robolectric.RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class UtilsTest {
@Test
diff --git a/app/src/test/java/ru/aleien/yapplication/database/DBBackendTest.java b/app/src/test/java/ru/aleien/yapplication/database/DBBackendTest.java
new file mode 100644
index 0000000..a3042ec
--- /dev/null
+++ b/app/src/test/java/ru/aleien/yapplication/database/DBBackendTest.java
@@ -0,0 +1,76 @@
+package ru.aleien.yapplication.database;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ru.aleien.yapplication.BuildConfig;
+import ru.aleien.yapplication.model.Artist;
+
+/**
+ * Created by aleien on 09.08.16.
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(constants = BuildConfig.class, sdk = 23)
+public class DBBackendTest {
+ DBHelper dbHelper = new DBHelper(RuntimeEnvironment.application, "testDB");
+ DBBackend dbBackend = new DBBackend(dbHelper);
+
+ @Before
+ public void setUp() throws Exception {
+
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ dbBackend.clearArtists();
+
+ }
+
+ @Test
+ public void insertArtist() throws Exception {
+ List genres = new ArrayList<>();
+ genres.add("pop");
+ genres.add("jazz");
+ Artist artist = new Artist(500, "Tove Lo", genres, 20, 2, "http://lalala.com", "Description", new Artist.Cover("http://firstimage", "http://seconimage"));
+ dbBackend.insertArtist(artist);
+
+ List artists = dbBackend.loadArtists();
+ Assert.assertEquals(artists.size(), 1);
+// Assert.assertTrue(artist.equals(artists.get(0)));
+ }
+
+ @Test
+ public void insertArtist1() throws Exception {
+
+ }
+
+ @Test
+ public void insertRelation() throws Exception {
+
+ }
+
+ @Test
+ public void insertGenres() throws Exception {
+
+ }
+
+ @Test
+ public void getAllArtists() throws Exception {
+
+ }
+
+ @Test
+ public void clearArtists() throws Exception {
+
+ }
+
+}
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index b206c45..0d7486e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,13 +5,15 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.0.0'
+ classpath 'com.android.tools.build:gradle:2.2.0-alpha7'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
- classpath 'me.tatarka:gradle-retrolambda:3.2.5'
+ classpath 'me.tatarka:gradle-retrolambda:3.3.0-beta4'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
+
+// configurations.classpath.exclude group: 'com.android.tools.external.lombok'
}
allprojects {
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index f37b0f3..00ece73 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Apr 10 21:36:34 MSK 2016
+#Wed Aug 10 00:21:08 MSK 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/keystore.properties b/keystore.properties
new file mode 100644
index 0000000..e69de29