mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Refresh button in library is now looking for new chapters in sources and notifying the user
This commit is contained in:
		| @@ -103,6 +103,11 @@ public class DatabaseHelper implements MangaManager, ChapterManager { | ||||
|         return mMangaManager.getMangasWithUnread(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Observable<List<Manga>> getFavoriteMangas() { | ||||
|         return mMangaManager.getFavoriteMangas(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Observable<List<Manga>> getManga(String url) { | ||||
|         return mMangaManager.getManga(url); | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
|  | ||||
| import eu.kanade.mangafeed.data.caches.CacheManager; | ||||
| import eu.kanade.mangafeed.sources.Batoto; | ||||
| import eu.kanade.mangafeed.sources.MangaHere; | ||||
| import eu.kanade.mangafeed.sources.base.Source; | ||||
| @@ -17,8 +16,6 @@ public class SourceManager { | ||||
|     public static final int MANGAHERE = 2; | ||||
|  | ||||
|     private HashMap<Integer, Source> mSourcesMap; | ||||
|     private NetworkHelper mNetworkHelper; | ||||
|     private CacheManager mCacheManager; | ||||
|     private Context context; | ||||
|  | ||||
|     public SourceManager(Context context) { | ||||
|   | ||||
| @@ -16,6 +16,8 @@ public interface MangaManager { | ||||
|  | ||||
|     Observable<List<Manga>> getMangasWithUnread(); | ||||
|  | ||||
|     Observable<List<Manga>> getFavoriteMangas(); | ||||
|  | ||||
|     Observable<List<Manga>> getManga(String url); | ||||
|  | ||||
|     Observable<List<Manga>> getManga(long id); | ||||
|   | ||||
| @@ -55,6 +55,19 @@ public class MangaManagerImpl extends BaseManager implements MangaManager { | ||||
|                 .createObservable(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Observable<List<Manga>> getFavoriteMangas() { | ||||
|         return db.get() | ||||
|                 .listOfObjects(Manga.class) | ||||
|                 .withQuery(Query.builder() | ||||
|                         .table(MangasTable.TABLE) | ||||
|                         .where(MangasTable.COLUMN_FAVORITE + "=?") | ||||
|                         .whereArgs(1) | ||||
|                         .build()) | ||||
|                 .prepare() | ||||
|                 .createObservable(); | ||||
|     } | ||||
|  | ||||
|     public Observable<List<Manga>> getManga(String url) { | ||||
|         return db.get() | ||||
|                 .listOfObjects(Manga.class) | ||||
|   | ||||
| @@ -0,0 +1,168 @@ | ||||
| package eu.kanade.mangafeed.data.services; | ||||
|  | ||||
| import android.app.Service; | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
|  | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
|  | ||||
| import javax.inject.Inject; | ||||
|  | ||||
| import eu.kanade.mangafeed.App; | ||||
| import eu.kanade.mangafeed.BuildConfig; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.helpers.DatabaseHelper; | ||||
| import eu.kanade.mangafeed.data.helpers.SourceManager; | ||||
| import eu.kanade.mangafeed.data.models.Manga; | ||||
| import eu.kanade.mangafeed.util.AndroidComponentUtil; | ||||
| import eu.kanade.mangafeed.util.NetworkUtil; | ||||
| import eu.kanade.mangafeed.util.NotificationUtil; | ||||
| import eu.kanade.mangafeed.util.PostResult; | ||||
| import rx.Observable; | ||||
| import rx.Subscription; | ||||
| import timber.log.Timber; | ||||
|  | ||||
| public class LibraryUpdateService extends Service { | ||||
|  | ||||
|     @Inject DatabaseHelper db; | ||||
|     @Inject SourceManager sourceManager; | ||||
|  | ||||
|     private Subscription updateSubscription; | ||||
|     private Subscription favoriteMangasSubscription; | ||||
|  | ||||
|     public static final int UPDATE_NOTIFICATION_ID = 1; | ||||
|  | ||||
|     public static Intent getStartIntent(Context context) { | ||||
|         return new Intent(context, LibraryUpdateService.class); | ||||
|     } | ||||
|  | ||||
|     public static boolean isRunning(Context context) { | ||||
|         return AndroidComponentUtil.isServiceRunning(context, LibraryUpdateService.class); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         App.get(this).getComponent().inject(this); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         if (updateSubscription != null) | ||||
|             updateSubscription.unsubscribe(); | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, final int startId) { | ||||
|         Timber.i("Starting sync..."); | ||||
|  | ||||
|         if (!NetworkUtil.isNetworkConnected(this)) { | ||||
|             Timber.i("Sync canceled, connection not available"); | ||||
|             AndroidComponentUtil.toggleComponent(this, SyncOnConnectionAvailable.class, true); | ||||
|             stopSelf(startId); | ||||
|             return START_NOT_STICKY; | ||||
|         } | ||||
|  | ||||
|         if (favoriteMangasSubscription != null && !favoriteMangasSubscription.isUnsubscribed()) | ||||
|             favoriteMangasSubscription.unsubscribe(); | ||||
|  | ||||
|         favoriteMangasSubscription = db.getFavoriteMangas() | ||||
|                 .subscribe(mangas -> { | ||||
|                     // Don't receive further db updates | ||||
|                     favoriteMangasSubscription.unsubscribe(); | ||||
|                     this.startUpdating(mangas, startId); | ||||
|                 }); | ||||
|  | ||||
|         return START_STICKY; | ||||
|     } | ||||
|  | ||||
|     private void startUpdating(final List<Manga> mangas, final int startId) { | ||||
|         if (updateSubscription != null && !updateSubscription.isUnsubscribed()) | ||||
|             updateSubscription.unsubscribe(); | ||||
|  | ||||
|         final AtomicInteger count = new AtomicInteger(0); | ||||
|  | ||||
|         List<MangaUpdate> updates = new ArrayList<>(); | ||||
|  | ||||
|         updateSubscription = Observable.from(mangas) | ||||
|                 .doOnNext(manga -> { | ||||
|                     NotificationUtil.create(this, UPDATE_NOTIFICATION_ID, | ||||
|                             getString(R.string.notification_progress, count.incrementAndGet(), mangas.size()), | ||||
|                             manga.title); | ||||
|                 }) | ||||
|                 .concatMap(manga -> sourceManager.get(manga.source) | ||||
|                                 .pullChaptersFromNetwork(manga.url) | ||||
|                                 .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters)) | ||||
|                                 .filter(result -> result.getNumberOfRowsInserted() > 0) | ||||
|                                 .flatMap(result -> Observable.just(new MangaUpdate(manga, result))) | ||||
|                 ) | ||||
|                 .subscribe(update -> { | ||||
|                     updates.add(update); | ||||
|                 }, error -> { | ||||
|                     Timber.e("Error syncing"); | ||||
|                     stopSelf(startId); | ||||
|                 }, () -> { | ||||
|                     NotificationUtil.createBigText(this, UPDATE_NOTIFICATION_ID, | ||||
|                             getString(R.string.notification_completed), getUpdatedMangas(updates)); | ||||
|                     stopSelf(startId); | ||||
|                 }); | ||||
|     } | ||||
|  | ||||
|     private String getUpdatedMangas(List<MangaUpdate> updates) { | ||||
|         final StringBuilder result = new StringBuilder(); | ||||
|         if (updates.isEmpty()) { | ||||
|             result.append(getString(R.string.notification_no_new_chapters)).append("\n"); | ||||
|         } else { | ||||
|             result.append(getString(R.string.notification_new_chapters)); | ||||
|  | ||||
|             for (MangaUpdate update : updates) { | ||||
|                 result.append("\n").append(update.getManga().title); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return result.toString(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static class SyncOnConnectionAvailable extends BroadcastReceiver { | ||||
|  | ||||
|         @Override | ||||
|         public void onReceive(Context context, Intent intent) { | ||||
|             if (NetworkUtil.isNetworkConnected(context)) { | ||||
|                 if (BuildConfig.DEBUG) { | ||||
|                     Timber.i("Connection is now available, triggering sync..."); | ||||
|                 } | ||||
|                 AndroidComponentUtil.toggleComponent(context, this.getClass(), false); | ||||
|                 context.startService(getStartIntent(context)); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class MangaUpdate { | ||||
|         private Manga manga; | ||||
|         private PostResult result; | ||||
|  | ||||
|         public MangaUpdate(Manga manga, PostResult result) { | ||||
|             this.manga = manga; | ||||
|             this.result = result; | ||||
|         } | ||||
|  | ||||
|         public Manga getManga() { | ||||
|             return manga; | ||||
|         } | ||||
|  | ||||
|         public PostResult getResult() { | ||||
|             return result; | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -5,6 +5,7 @@ import android.app.Application; | ||||
| import javax.inject.Singleton; | ||||
|  | ||||
| import dagger.Component; | ||||
| import eu.kanade.mangafeed.data.services.LibraryUpdateService; | ||||
| import eu.kanade.mangafeed.injection.module.AppModule; | ||||
| import eu.kanade.mangafeed.injection.module.DataModule; | ||||
| import eu.kanade.mangafeed.presenter.CataloguePresenter; | ||||
| @@ -40,6 +41,8 @@ public interface AppComponent { | ||||
|  | ||||
|     void inject(Source source); | ||||
|  | ||||
|     void inject(LibraryUpdateService libraryUpdateService); | ||||
|  | ||||
|     Application application(); | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -19,6 +19,7 @@ import butterknife.ButterKnife; | ||||
| import butterknife.OnItemClick; | ||||
| import eu.kanade.mangafeed.R; | ||||
| import eu.kanade.mangafeed.data.models.Manga; | ||||
| import eu.kanade.mangafeed.data.services.LibraryUpdateService; | ||||
| import eu.kanade.mangafeed.presenter.LibraryPresenter; | ||||
| import eu.kanade.mangafeed.ui.activity.MainActivity; | ||||
| import eu.kanade.mangafeed.ui.activity.MangaDetailActivity; | ||||
| @@ -68,6 +69,21 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> { | ||||
|         initializeSearch(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         switch (item.getItemId()) { | ||||
|             case R.id.action_refresh: | ||||
|                 if (!LibraryUpdateService.isRunning(activity)) { | ||||
|                     Intent intent = LibraryUpdateService.getStartIntent(activity); | ||||
|                     activity.startService(intent); | ||||
|                 } | ||||
|  | ||||
|                 return true; | ||||
|         } | ||||
|  | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
|     private void initializeSearch(Menu menu) { | ||||
|         final SearchView sv = (SearchView) menu.findItem(R.id.action_search).getActionView(); | ||||
|         sv.setOnQueryTextListener(new SearchView.OnQueryTextListener() { | ||||
|   | ||||
| @@ -0,0 +1,33 @@ | ||||
| package eu.kanade.mangafeed.util; | ||||
|  | ||||
| import android.app.ActivityManager; | ||||
| import android.app.ActivityManager.RunningServiceInfo; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.pm.PackageManager; | ||||
|  | ||||
| import timber.log.Timber; | ||||
|  | ||||
| public class AndroidComponentUtil { | ||||
|  | ||||
|     public static void toggleComponent(Context context, Class componentClass, boolean enable) { | ||||
|         Timber.i((enable ? "Enabling " : "Disabling ") + componentClass.getSimpleName()); | ||||
|         ComponentName componentName = new ComponentName(context, componentClass); | ||||
|         PackageManager pm = context.getPackageManager(); | ||||
|         pm.setComponentEnabledSetting(componentName, | ||||
|                 enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : | ||||
|                         PackageManager.COMPONENT_ENABLED_STATE_DISABLED, | ||||
|                 PackageManager.DONT_KILL_APP); | ||||
|     } | ||||
|  | ||||
|     public static boolean isServiceRunning(Context context, Class serviceClass) { | ||||
|         ActivityManager manager = | ||||
|                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { | ||||
|             if (serviceClass.getName().equals(service.service.getClassName())) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,44 @@ | ||||
| package eu.kanade.mangafeed.util; | ||||
|  | ||||
| import android.app.NotificationManager; | ||||
| import android.content.Context; | ||||
| import android.support.v4.app.NotificationCompat; | ||||
|  | ||||
| import eu.kanade.mangafeed.R; | ||||
|  | ||||
| public class NotificationUtil { | ||||
|  | ||||
|     public static void create(Context context, int nId, String title, String body, int iconRes) { | ||||
|         NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) | ||||
|                 .setSmallIcon(iconRes == -1 ? R.drawable.ic_action_refresh : iconRes) | ||||
|                 .setContentTitle(title) | ||||
|                 .setContentText(body); | ||||
|  | ||||
|  | ||||
|         NotificationManager mNotificationManager = | ||||
|                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|  | ||||
|         mNotificationManager.notify(nId, mBuilder.build()); | ||||
|     } | ||||
|  | ||||
|     public static void createBigText(Context context, int nId, String title, String body, int iconRes) { | ||||
|         NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context) | ||||
|                 .setSmallIcon(iconRes == -1 ? R.drawable.ic_action_refresh : iconRes) | ||||
|                 .setContentTitle(title) | ||||
|                 .setStyle(new NotificationCompat.BigTextStyle().bigText(body)); | ||||
|  | ||||
|         NotificationManager mNotificationManager = | ||||
|                 (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|  | ||||
|         mNotificationManager.notify(nId, mBuilder.build()); | ||||
|     } | ||||
|  | ||||
|     public static void create(Context context, int nId, String title, String body) { | ||||
|         create(context, nId, title, body, -1); | ||||
|     } | ||||
|  | ||||
|     public static void createBigText(Context context, int nId, String title, String body) { | ||||
|         createBigText(context, nId, title, body, -1); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -19,17 +19,14 @@ public class PostResult { | ||||
|         this.numberOfRowsDeleted = numberOfRowsDeleted; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public Integer getNumberOfRowsUpdated() { | ||||
|         return numberOfRowsUpdated; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public Integer getNumberOfRowsInserted() { | ||||
|         return numberOfRowsInserted; | ||||
|     } | ||||
|  | ||||
|     @Nullable | ||||
|     public Integer getNumberOfRowsDeleted() { | ||||
|         return numberOfRowsDeleted; | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user