mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Allow to update one category
This commit is contained in:
		| @@ -14,6 +14,7 @@ import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork | ||||
| import eu.kanade.tachiyomi.App | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.DatabaseHelper | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.data.source.SourceManager | ||||
| @@ -36,38 +37,51 @@ import javax.inject.Inject | ||||
|  */ | ||||
| class LibraryUpdateService : Service() { | ||||
|  | ||||
|     // Dependencies injected through dagger. | ||||
|     /** | ||||
|      * Database helper. | ||||
|      */ | ||||
|     @Inject lateinit var db: DatabaseHelper | ||||
|  | ||||
|     /** | ||||
|      * Source manager. | ||||
|      */ | ||||
|     @Inject lateinit var sourceManager: SourceManager | ||||
|  | ||||
|     /** | ||||
|      * Preferences. | ||||
|      */ | ||||
|     @Inject lateinit var preferences: PreferencesHelper | ||||
|  | ||||
|     // Wake lock that will be held until the service is destroyed. | ||||
|     /** | ||||
|      * Wake lock that will be held until the service is destroyed. | ||||
|      */ | ||||
|     private lateinit var wakeLock: PowerManager.WakeLock | ||||
|  | ||||
|     // Subscription where the update is done. | ||||
|     /** | ||||
|      * Subscription where the update is done. | ||||
|      */ | ||||
|     private var subscription: Subscription? = null | ||||
|  | ||||
|  | ||||
|     companion object { | ||||
|         val UPDATE_NOTIFICATION_ID = 1 | ||||
|  | ||||
|         // Intent key for manual library update | ||||
|         val UPDATE_IS_MANUAL = "is_manual" | ||||
|         /** | ||||
|          * Id of the library update notification. | ||||
|          */ | ||||
|         const val UPDATE_NOTIFICATION_ID = 1 | ||||
|  | ||||
|         /** | ||||
|          * Get the start intent for [LibraryUpdateService]. | ||||
|          * @param context the application context. | ||||
|          * @param isManual true when user triggers library update. | ||||
|          * @return the intent of the service. | ||||
|          * Key for manual library update. | ||||
|          */ | ||||
|         fun getIntent(context: Context, isManual: Boolean = false): Intent { | ||||
|             return Intent(context, LibraryUpdateService::class.java).apply { | ||||
|                 putExtra(UPDATE_IS_MANUAL, isManual) | ||||
|             } | ||||
|         } | ||||
|         const val UPDATE_IS_MANUAL = "is_manual" | ||||
|  | ||||
|         /** | ||||
|          * Key for category to update. | ||||
|          */ | ||||
|         const val UPDATE_CATEGORY = "category" | ||||
|  | ||||
|         /** | ||||
|          * Returns the status of the service. | ||||
|          * | ||||
|          * @param context the application context. | ||||
|          * @return true if the service is running, false otherwise. | ||||
|          */ | ||||
| @@ -76,19 +90,30 @@ class LibraryUpdateService : Service() { | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Static method to start the service. It will be started only if there isn't another | ||||
|          * instance already running. | ||||
|          * Starts the service. It will be started only if there isn't another instance already | ||||
|          * running. | ||||
|          * | ||||
|          * @param context the application context. | ||||
|          * @param isManual whether the update has been manually triggered. | ||||
|          * @param category a specific category to update, or null for all in the library. | ||||
|          */ | ||||
|         @JvmStatic | ||||
|         fun start(context: Context, isForced: Boolean = false) { | ||||
|         fun start(context: Context, isManual: Boolean = false, category: Category? = null) { | ||||
|             if (!isRunning(context)) { | ||||
|                 context.startService(getIntent(context, isForced)) | ||||
|                 val intent = Intent(context, LibraryUpdateService::class.java).apply { | ||||
|                     putExtra(UPDATE_IS_MANUAL, isManual) | ||||
|                     category?.let { putExtra(UPDATE_CATEGORY, it.id) } | ||||
|                 } | ||||
|                 context.startService(intent) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         /** | ||||
|          * Stops the service. | ||||
|          * | ||||
|          * @param context the application context. | ||||
|          */ | ||||
|         fun stop(context: Context) { | ||||
|             context.stopService(getIntent(context)) | ||||
|             context.stopService(Intent(context, LibraryUpdateService::class.java)) | ||||
|         } | ||||
|  | ||||
|     } | ||||
| @@ -104,7 +129,7 @@ class LibraryUpdateService : Service() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method called when the service is destroyed. It destroy the running subscription, resets | ||||
|      * Method called when the service is destroyed. It destroys the running subscription, resets | ||||
|      * the alarm and release the wake lock. | ||||
|      */ | ||||
|     override fun onDestroy() { | ||||
| @@ -121,9 +146,9 @@ class LibraryUpdateService : Service() { | ||||
|         return null | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Method called when the service receives an intent. | ||||
|      * | ||||
|      * @param intent the start intent from. | ||||
|      * @param flags the flags of the command. | ||||
|      * @param startId the start id of this command. | ||||
| @@ -145,7 +170,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|         // Check if device has internet connection | ||||
|         // Check if device has wifi connection if only wifi is enabled | ||||
|         if (connection == ConnectivityStatus.OFFLINE || ("wifi" in restrictions | ||||
|         if (connection == ConnectivityStatus.OFFLINE || (!isManualUpdate && "wifi" in restrictions | ||||
|                 && connection != ConnectivityStatus.WIFI_CONNECTED_HAS_INTERNET)) { | ||||
|  | ||||
|             if (isManualUpdate) { | ||||
| @@ -174,7 +199,7 @@ class LibraryUpdateService : Service() { | ||||
|         subscription?.unsubscribe() | ||||
|  | ||||
|         // Update favorite manga. Destroy service when completed or in case of an error. | ||||
|         subscription = Observable.defer { updateLibrary() } | ||||
|         subscription = Observable.defer { updateMangaList(getMangaToUpdate(intent)) } | ||||
|                 .subscribeOn(Schedulers.io()) | ||||
|                 .subscribe({}, | ||||
|                         { | ||||
| @@ -188,13 +213,36 @@ class LibraryUpdateService : Service() { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method that updates the library. It's called in a background thread, so it's safe to do | ||||
|      * heavy operations or network calls here. | ||||
|      * Returns the list of manga to be updated. | ||||
|      * | ||||
|      * @param intent the update intent. | ||||
|      * @return a list of manga to update | ||||
|      */ | ||||
|     fun getMangaToUpdate(intent: Intent?): List<Manga> { | ||||
|         val categoryId = intent?.getIntExtra(UPDATE_CATEGORY, -1) ?: -1 | ||||
|  | ||||
|         var toUpdate = if (categoryId != -1) | ||||
|             db.getLibraryMangas().executeAsBlocking().filter { it.category == categoryId } | ||||
|         else | ||||
|             db.getFavoriteMangas().executeAsBlocking() | ||||
|  | ||||
|         if (preferences.updateOnlyNonCompleted()) { | ||||
|             toUpdate = toUpdate.filter { it.status != Manga.COMPLETED } | ||||
|         } | ||||
|  | ||||
|         return toUpdate | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Method that updates the given list of manga. It's called in a background thread, so it's safe | ||||
|      * to do heavy operations or network calls here. | ||||
|      * For each manga it calls [updateManga] and updates the notification showing the current | ||||
|      * progress. | ||||
|      * | ||||
|      * @param mangaToUpdate the list to update | ||||
|      * @return an observable delivering the progress of each update. | ||||
|      */ | ||||
|     fun updateLibrary(): Observable<Manga> { | ||||
|     fun updateMangaList(mangaToUpdate: List<Manga>): Observable<Manga> { | ||||
|         // Initialize the variables holding the progress of the updates. | ||||
|         val count = AtomicInteger(0) | ||||
|         val newUpdates = ArrayList<Manga>() | ||||
| @@ -203,17 +251,10 @@ class LibraryUpdateService : Service() { | ||||
|         val cancelIntent = PendingIntent.getBroadcast(this, 0, | ||||
|                 Intent(this, CancelUpdateReceiver::class.java), 0) | ||||
|  | ||||
|         // Get the manga list that is going to be updated. | ||||
|         val allLibraryMangas = db.getFavoriteMangas().executeAsBlocking() | ||||
|         val toUpdate = if (!preferences.updateOnlyNonCompleted()) | ||||
|             allLibraryMangas | ||||
|         else | ||||
|             allLibraryMangas.filter { it.status != Manga.COMPLETED } | ||||
|  | ||||
|         // Emit each manga and update it sequentially. | ||||
|         return Observable.from(toUpdate) | ||||
|         return Observable.from(mangaToUpdate) | ||||
|                 // Notify manga that will update. | ||||
|                 .doOnNext { showProgressNotification(it, count.andIncrement, toUpdate.size, cancelIntent) } | ||||
|                 .doOnNext { showProgressNotification(it, count.andIncrement, mangaToUpdate.size, cancelIntent) } | ||||
|                 // Update the chapters of the manga. | ||||
|                 .concatMap { manga -> | ||||
|                     updateManga(manga) | ||||
| @@ -241,6 +282,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|     /** | ||||
|      * Updates the chapters for the given manga and adds them to the database. | ||||
|      * | ||||
|      * @param manga the manga to update. | ||||
|      * @return a pair of the inserted and removed chapters. | ||||
|      */ | ||||
| @@ -253,6 +295,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|     /** | ||||
|      * Returns the text that will be displayed in the notification when there are new chapters. | ||||
|      * | ||||
|      * @param updates a list of manga that contains new chapters. | ||||
|      * @param failedUpdates a list of manga that failed to update. | ||||
|      * @return the body of the notification to display. | ||||
| @@ -301,6 +344,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|     /** | ||||
|      * Shows the notification with the given title and body. | ||||
|      * | ||||
|      * @param title the title of the notification. | ||||
|      * @param body the body of the notification. | ||||
|      */ | ||||
| @@ -314,6 +358,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|     /** | ||||
|      * Shows the notification containing the currently updating manga and the progress. | ||||
|      * | ||||
|      * @param manga the manga that's being updated. | ||||
|      * @param current the current progress. | ||||
|      * @param total the total progress. | ||||
| @@ -331,6 +376,7 @@ class LibraryUpdateService : Service() { | ||||
|  | ||||
|     /** | ||||
|      * Shows the notification containing the result of the update done by the service. | ||||
|      * | ||||
|      * @param updates a list of manga with new updates. | ||||
|      * @param failed a list of manga that failed to update. | ||||
|      */ | ||||
| @@ -371,6 +417,7 @@ class LibraryUpdateService : Service() { | ||||
|     class SyncOnConnectionAvailable : BroadcastReceiver() { | ||||
|         /** | ||||
|          * Method called when a network change occurs. | ||||
|          * | ||||
|          * @param context the application context. | ||||
|          * @param intent the intent received. | ||||
|          */ | ||||
| @@ -388,6 +435,7 @@ class LibraryUpdateService : Service() { | ||||
|     class SyncOnPowerConnected: BroadcastReceiver() { | ||||
|         /** | ||||
|          * Method called when AC is connected. | ||||
|          * | ||||
|          * @param context the application context. | ||||
|          * @param intent the intent received. | ||||
|          */ | ||||
| @@ -403,6 +451,7 @@ class LibraryUpdateService : Service() { | ||||
|     class CancelUpdateReceiver : BroadcastReceiver() { | ||||
|         /** | ||||
|          * Method called when user wants a library update. | ||||
|          *  | ||||
|          * @param context the application context. | ||||
|          * @param intent the intent received. | ||||
|          */ | ||||
|   | ||||
| @@ -156,8 +156,8 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback | ||||
|             searchView.clearFocus() | ||||
|         } | ||||
|  | ||||
|         filterDownloadedItem.isChecked = isFilterDownloaded; | ||||
|         filterUnreadItem.isChecked = isFilterUnread; | ||||
|         filterDownloadedItem.isChecked = isFilterDownloaded | ||||
|         filterUnreadItem.isChecked = isFilterUnread | ||||
|  | ||||
|         searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener { | ||||
|             override fun onQueryTextSubmit(query: String): Boolean { | ||||
| @@ -200,7 +200,13 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback | ||||
|                 // Apply filter | ||||
|                 onFilterCheckboxChanged() | ||||
|             } | ||||
|             R.id.action_refresh -> LibraryUpdateService.start(activity, true) // Force refresh | ||||
|             R.id.action_update_library -> { | ||||
|                 LibraryUpdateService.start(activity, true) | ||||
|             } | ||||
|             R.id.action_update_category -> { | ||||
|                 val category = presenter.categories[view_pager.currentItem] | ||||
|                 LibraryUpdateService.start(activity, true, category) | ||||
|             } | ||||
|             R.id.action_edit_categories -> { | ||||
|                 val intent = CategoryActivity.newIntent(activity) | ||||
|                 startActivity(intent) | ||||
| @@ -218,7 +224,7 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback | ||||
|         presenter.updateLibrary() | ||||
|         adapter.notifyDataSetChanged() | ||||
|         adapter.refreshRegisteredAdapters() | ||||
|         activity.supportInvalidateOptionsMenu(); | ||||
|         activity.supportInvalidateOptionsMenu() | ||||
|     } | ||||
|  | ||||
|     /** | ||||
| @@ -249,12 +255,10 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback | ||||
|         // Get the current active category. | ||||
|         val activeCat = if (adapter.categories != null) view_pager.currentItem else activeCategory | ||||
|  | ||||
|         // Add the default category if it contains manga. | ||||
|         if (mangaMap[0] != null) { | ||||
|             setCategories(arrayListOf(Category.createDefault()) + categories) | ||||
|         } else { | ||||
|             setCategories(categories) | ||||
|         } | ||||
|         // Set the categories | ||||
|         adapter.categories = categories | ||||
|         tabs.setupWithViewPager(view_pager) | ||||
|         tabs.visibility = if (categories.size <= 1) View.GONE else View.VISIBLE | ||||
|  | ||||
|         // Restore active category. | ||||
|         view_pager.setCurrentItem(activeCat, false) | ||||
| @@ -270,17 +274,6 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback | ||||
|         presenter.libraryMangaSubject.onNext(LibraryMangaEvent(mangaMap)) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the categories in the adapter and the tab layout. | ||||
|      * | ||||
|      * @param categories the categories to set. | ||||
|      */ | ||||
|     private fun setCategories(categories: List<Category>) { | ||||
|         adapter.categories = categories | ||||
|         tabs.setupWithViewPager(view_pager) | ||||
|         tabs.visibility = if (categories.size <= 1) View.GONE else View.VISIBLE | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Sets the title of the action mode. | ||||
|      * | ||||
|   | ||||
| @@ -98,7 +98,15 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() { | ||||
|      */ | ||||
|     fun getLibraryObservable(): Observable<Pair<List<Category>, Map<Int, List<Manga>>>> { | ||||
|         return Observable.combineLatest(getCategoriesObservable(), getLibraryMangasObservable(), | ||||
|                 { a, b -> Pair(a, b) }) | ||||
|                 { dbCategories, libraryManga -> | ||||
|                     val categories = if (libraryManga.containsKey(0)) | ||||
|                         arrayListOf(Category.createDefault()) + dbCategories | ||||
|                     else | ||||
|                         dbCategories | ||||
|  | ||||
|                     this.categories = categories | ||||
|                     Pair(categories, libraryManga) | ||||
|                 }) | ||||
|                 .observeOn(AndroidSchedulers.mainThread()) | ||||
|     } | ||||
|  | ||||
| @@ -109,7 +117,6 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() { | ||||
|      */ | ||||
|     fun getCategoriesObservable(): Observable<List<Category>> { | ||||
|         return db.getCategories().asRxObservable() | ||||
|                 .doOnNext { categories -> this.categories = categories } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -30,11 +30,16 @@ | ||||
|         app:actionViewClass="android.support.v7.widget.SearchView" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_refresh" | ||||
|         android:title="@string/action_refresh" | ||||
|         android:id="@+id/action_update_library" | ||||
|         android:title="@string/action_update_library" | ||||
|         android:icon="@drawable/ic_refresh_white_24dp" | ||||
|         app:showAsAction="ifRoom" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_update_category" | ||||
|         android:title="@string/action_update_category" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_edit_categories" | ||||
|         android:title="@string/action_edit_categories" | ||||
|   | ||||
| @@ -20,7 +20,6 @@ | ||||
|     <string name="action_filter_unread">Unread</string> | ||||
|     <string name="action_filter_empty">Remove filter</string> | ||||
|     <string name="action_search">Search</string> | ||||
|     <string name="action_refresh">Refresh</string> | ||||
|     <string name="action_select_all">Select all</string> | ||||
|     <string name="action_mark_as_read">Mark as read</string> | ||||
|     <string name="action_mark_as_unread">Mark as unread</string> | ||||
| @@ -28,6 +27,8 @@ | ||||
|     <string name="action_download">Download</string> | ||||
|     <string name="action_delete">Delete</string> | ||||
|     <string name="action_update">Update</string> | ||||
|     <string name="action_update_library">Update library</string> | ||||
|     <string name="action_update_category">Update active category</string> | ||||
|     <string name="action_edit">Edit</string> | ||||
|     <string name="action_add_category">Add category</string> | ||||
|     <string name="action_edit_categories">Edit categories</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user