Ver código fonte

Add an option to update the library automatically after a specified time and an option to update only non completed mangas. Other minor changes.

inorichi 9 anos atrás
pai
commit
fcb5bf4dd4

+ 2 - 2
app/build.gradle

@@ -89,8 +89,8 @@ dependencies {
     compile "com.android.support:design:$SUPPORT_LIBRARY_VERSION"
     compile "com.android.support:recyclerview-v7:$SUPPORT_LIBRARY_VERSION"
     compile "com.android.support:support-annotations:$SUPPORT_LIBRARY_VERSION"
-    compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.0'
-    compile 'com.squareup.okhttp:okhttp:2.7.0'
+    compile 'com.squareup.okhttp:okhttp-urlconnection:2.7.2'
+    compile 'com.squareup.okhttp:okhttp:2.7.2'
     compile 'com.squareup.okio:okio:1.6.0'
     compile 'com.google.code.gson:gson:2.5'
     compile 'com.jakewharton:disklrucache:2.0.2'

+ 9 - 0
app/src/main/AndroidManifest.xml

@@ -6,6 +6,7 @@
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
 
     <application
         android:name=".App"
@@ -67,6 +68,14 @@
             </intent-filter>
         </receiver>
 
+        <receiver
+            android:name=".data.sync.LibraryUpdateAlarm">
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED"/>
+                <action android:name="eu.kanade.UPDATE_LIBRARY" />
+            </intent-filter>
+        </receiver>
+
         <meta-data
             android:name="eu.kanade.mangafeed.data.cache.CoverGlideModule"
             android:value="GlideModule" />

+ 2 - 2
app/src/main/java/eu/kanade/mangafeed/data/network/NetworkHelper.java

@@ -44,7 +44,7 @@ public final class NetworkHelper {
             } catch (Throwable e) {
                 return Observable.error(e);
             }
-        }).retry(2);
+        }).retry(1);
     }
 
     public Observable<String> mapResponseToString(final Response response) {
@@ -74,7 +74,7 @@ public final class NetworkHelper {
             } catch (Throwable e) {
                 return Observable.error(e);
             }
-        }).retry(2);
+        }).retry(1);
     }
 
     public Observable<Response> getProgressResponse(final String url, final Headers headers, final ProgressListener listener) {

+ 9 - 0
app/src/main/java/eu/kanade/mangafeed/data/preference/PreferencesHelper.java

@@ -97,6 +97,10 @@ public class PreferencesHelper {
         return rxPrefs.getInteger(getKey(R.string.pref_library_columns_landscape_key), 0);
     }
 
+    public boolean updateOnlyNonCompleted() {
+        return prefs.getBoolean(getKey(R.string.pref_update_only_non_completed_key), false);
+    }
+
     public Preference<Integer> imageDecoder() {
         return rxPrefs.getInteger(getKey(R.string.pref_image_decoder_key), 0);
     }
@@ -148,4 +152,9 @@ public class PreferencesHelper {
         return rxPrefs.getInteger(getKey(R.string.pref_download_slots_key), 1);
     }
 
+    public static int getLibraryUpdateInterval(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context).getInt(
+                context.getString(R.string.pref_library_update_interval_key), 0);
+    }
+
 }

+ 62 - 0
app/src/main/java/eu/kanade/mangafeed/data/sync/LibraryUpdateAlarm.java

@@ -0,0 +1,62 @@
+package eu.kanade.mangafeed.data.sync;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+
+import eu.kanade.mangafeed.data.preference.PreferencesHelper;
+import timber.log.Timber;
+
+public class LibraryUpdateAlarm extends BroadcastReceiver {
+
+    public static final String LIBRARY_UPDATE_ACTION = "eu.kanade.UPDATE_LIBRARY";
+
+    public static void startAlarm(Context context) {
+        startAlarm(context, PreferencesHelper.getLibraryUpdateInterval(context));
+    }
+
+    public static void startAlarm(Context context, int intervalInHours) {
+        stopAlarm(context);
+        if (intervalInHours == 0)
+            return;
+
+        int intervalInMillis = intervalInHours * 60 * 60 * 1000;
+        long nextRun = SystemClock.elapsedRealtime() + intervalInMillis;
+
+        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        PendingIntent pendingIntent = getPendingIntent(context);
+        alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                nextRun, intervalInMillis, pendingIntent);
+
+        Timber.i("Alarm set. Library will update on " + nextRun);
+    }
+
+    public static void stopAlarm(Context context) {
+        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        PendingIntent pendingIntent = getPendingIntent(context);
+        alarmManager.cancel(pendingIntent);
+    }
+
+    private static PendingIntent getPendingIntent(Context context) {
+        Intent intent = new Intent(context, LibraryUpdateAlarm.class);
+        intent.setAction(LIBRARY_UPDATE_ACTION);
+        return PendingIntent.getBroadcast(context, 0, intent, 0);
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (intent.getAction() == null)
+            return;
+
+        if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
+            startAlarm(context);
+        } else if (intent.getAction().equals(LIBRARY_UPDATE_ACTION)) {
+            LibraryUpdateService.start(context);
+        }
+
+    }
+
+}

+ 63 - 34
app/src/main/java/eu/kanade/mangafeed/data/sync/LibraryUpdateService.java

@@ -17,6 +17,7 @@ import eu.kanade.mangafeed.BuildConfig;
 import eu.kanade.mangafeed.R;
 import eu.kanade.mangafeed.data.database.DatabaseHelper;
 import eu.kanade.mangafeed.data.database.models.Manga;
+import eu.kanade.mangafeed.data.preference.PreferencesHelper;
 import eu.kanade.mangafeed.data.source.SourceManager;
 import eu.kanade.mangafeed.util.AndroidComponentUtil;
 import eu.kanade.mangafeed.util.NetworkUtil;
@@ -31,16 +32,23 @@ public class LibraryUpdateService extends Service {
 
     @Inject DatabaseHelper db;
     @Inject SourceManager sourceManager;
+    @Inject PreferencesHelper preferences;
 
-    private Subscription updateSubscription;
+    private Subscription subscription;
 
     public static final int UPDATE_NOTIFICATION_ID = 1;
 
-    public static Intent getStartIntent(Context context) {
+    public static void start(Context context) {
+        if (!isRunning(context)) {
+            context.startService(getStartIntent(context));
+        }
+    }
+
+    private static Intent getStartIntent(Context context) {
         return new Intent(context, LibraryUpdateService.class);
     }
 
-    public static boolean isRunning(Context context) {
+    private static boolean isRunning(Context context) {
         return AndroidComponentUtil.isServiceRunning(context, LibraryUpdateService.class);
     }
 
@@ -52,8 +60,10 @@ public class LibraryUpdateService extends Service {
 
     @Override
     public void onDestroy() {
-        if (updateSubscription != null)
-            updateSubscription.unsubscribe();
+        if (subscription != null)
+            subscription.unsubscribe();
+        // Reset the alarm
+        LibraryUpdateAlarm.startAlarm(this);
         super.onDestroy();
     }
 
@@ -68,44 +78,56 @@ public class LibraryUpdateService extends Service {
             return START_NOT_STICKY;
         }
 
-        Observable.fromCallable(() -> db.getFavoriteMangas().executeAsBlocking())
+        subscription = Observable.fromCallable(() -> db.getFavoriteMangas().executeAsBlocking())
                 .subscribeOn(Schedulers.io())
-                .subscribe(mangas -> {
-                    startUpdating(mangas, startId);
-                });
+                .flatMap(this::updateLibrary)
+                .subscribe(next -> {},
+                        error -> {
+                            NotificationUtil.create(this, UPDATE_NOTIFICATION_ID,
+                                    getString(R.string.notification_update_error), "");
+                            stopSelf(startId);
+                        }, () -> {
+                            Timber.i("Library updated");
+                            stopSelf(startId);
+                        });
 
         return START_STICKY;
     }
 
-    private void startUpdating(final List<Manga> mangas, final int startId) {
+    private Observable<MangaUpdate> updateLibrary(List<Manga> allLibraryMangas) {
         final AtomicInteger count = new AtomicInteger(0);
+        final List<MangaUpdate> updates = new ArrayList<>();
+        final List<Manga> failedUpdates = new ArrayList<>();
+
+        final List<Manga> mangas = !preferences.updateOnlyNonCompleted() ? allLibraryMangas :
+            Observable.from(allLibraryMangas)
+                    .filter(manga -> manga.status != Manga.COMPLETED)
+                    .toList().toBlocking().single();
+
+        return Observable.from(mangas)
+                .doOnNext(manga -> NotificationUtil.create(this, UPDATE_NOTIFICATION_ID,
+                        getString(R.string.notification_update_progress,
+                                count.incrementAndGet(), mangas.size()), manga.title))
+                .concatMap(manga -> updateManga(manga)
+                        .onErrorReturn(error -> {
+                            failedUpdates.add(manga);
+                            return new PostResult(0, 0, 0);
+                        })
+                        .filter(result -> result.getNumberOfRowsInserted() > 0)
+                        .map(result -> new MangaUpdate(manga, result)))
+                .doOnNext(updates::add)
+                .doOnCompleted(() -> NotificationUtil.createBigText(this, UPDATE_NOTIFICATION_ID,
+                        getString(R.string.notification_update_completed),
+                        getUpdatedMangas(updates, failedUpdates)));
+    }
 
-        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 Observable<PostResult> updateManga(Manga manga) {
+        return sourceManager.get(manga.source)
+                .pullChaptersFromNetwork(manga.url)
+                .flatMap(chapters -> db.insertOrRemoveChapters(manga, chapters));
     }
 
-    private String getUpdatedMangas(List<MangaUpdate> updates) {
+    private String getUpdatedMangas(List<MangaUpdate> updates, List<Manga> failedUpdates) {
         final StringBuilder result = new StringBuilder();
         if (updates.isEmpty()) {
             result.append(getString(R.string.notification_no_new_chapters)).append("\n");
@@ -116,6 +138,13 @@ public class LibraryUpdateService extends Service {
                 result.append("\n").append(update.getManga().title);
             }
         }
+        if (!failedUpdates.isEmpty()) {
+            result.append("\n");
+            result.append(getString(R.string.notification_manga_update_failed));
+            for (Manga manga : failedUpdates) {
+                result.append("\n").append(manga.title);
+            }
+        }
 
         return result.toString();
     }

+ 1 - 4
app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java

@@ -105,10 +105,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.action_refresh:
-                if (!LibraryUpdateService.isRunning(getActivity())) {
-                    Intent intent = LibraryUpdateService.getStartIntent(getActivity());
-                    getActivity().startService(intent);
-                }
+                LibraryUpdateService.start(getActivity());
                 return true;
             case R.id.action_edit_categories:
                 onEditCategories();

+ 11 - 3
app/src/main/java/eu/kanade/mangafeed/ui/setting/SettingsGeneralFragment.java

@@ -7,12 +7,12 @@ import android.view.ViewGroup;
 
 import eu.kanade.mangafeed.R;
 import eu.kanade.mangafeed.data.preference.PreferencesHelper;
+import eu.kanade.mangafeed.data.sync.LibraryUpdateAlarm;
+import eu.kanade.mangafeed.ui.setting.preference.IntListPreference;
 import eu.kanade.mangafeed.ui.setting.preference.LibraryColumnsDialog;
 
 public class SettingsGeneralFragment extends SettingsNestedFragment {
 
-    private LibraryColumnsDialog columnsDialog;
-
     public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
         SettingsNestedFragment fragment = new SettingsGeneralFragment();
         fragment.setArgs(resourcePreference, resourceTitle);
@@ -25,11 +25,19 @@ public class SettingsGeneralFragment extends SettingsNestedFragment {
 
         PreferencesHelper preferences = getSettingsActivity().preferences;
 
-        columnsDialog = (LibraryColumnsDialog) findPreference(
+        LibraryColumnsDialog columnsDialog = (LibraryColumnsDialog) findPreference(
                 getString(R.string.pref_library_columns_dialog_key));
 
         columnsDialog.setPreferencesHelper(preferences);
 
+        IntListPreference updateInterval = (IntListPreference) findPreference(
+                getString(R.string.pref_library_update_interval_key));
+
+        updateInterval.setOnPreferenceChangeListener((preference, newValue) -> {
+            LibraryUpdateAlarm.startAlarm(getActivity(), Integer.parseInt((String) newValue));
+            return true;
+        });
+
         return view;
     }
 

BIN
app/src/main/res/drawable-xhdpi/card_background.9.png


+ 22 - 0
app/src/main/res/values/arrays.xml

@@ -48,4 +48,26 @@
         <item>1</item>
     </string-array>
 
+    <string-array name="library_update_interval">
+        <item>@string/update_never</item>
+        <item>@string/update_1hour</item>
+        <item>@string/update_2hour</item>
+        <item>@string/update_3hour</item>
+        <item>@string/update_6hour</item>
+        <item>@string/update_12hour</item>
+        <item>@string/update_24hour</item>
+        <item>@string/update_48hour</item>
+    </string-array>
+
+    <string-array name="library_update_interval_values">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>6</item>
+        <item>12</item>
+        <item>24</item>
+        <item>48</item>
+    </string-array>
+
 </resources>

+ 2 - 0
app/src/main/res/values/keys.xml

@@ -10,6 +10,8 @@
     <string name="pref_library_columns_dialog_key">pref_library_columns_dialog_key</string>
     <string name="pref_library_columns_portrait_key">pref_library_columns_portrait_key</string>
     <string name="pref_library_columns_landscape_key">pref_library_columns_landscape_key</string>
+    <string name="pref_library_update_interval_key">pref_library_update_interval_key</string>
+    <string name="pref_update_only_non_completed_key">pref_update_only_non_completed_key</string>
 
     <string name="pref_default_viewer_key">pref_default_viewer_key</string>
     <string name="pref_hide_status_bar_key">pref_hide_status_bar_key</string>

+ 14 - 2
app/src/main/res/values/strings.xml

@@ -63,6 +63,16 @@
     <string name="portrait">Portrait</string>
     <string name="landscape">Landscape</string>
     <string name="default_columns">Default</string>
+    <string name="pref_library_update_interval">Library update period</string>
+    <string name="pref_update_only_non_completed">Update only non completed mangas</string>
+    <string name="update_never">Manual</string>
+    <string name="update_1hour">Hourly</string>
+    <string name="update_2hour">Every 2 hours</string>
+    <string name="update_3hour">Every 3 hours</string>
+    <string name="update_6hour">Every 6 hours</string>
+    <string name="update_12hour">Every 12 hours</string>
+    <string name="update_24hour">Daily</string>
+    <string name="update_48hour">Every 2 days</string>
 
       <!-- Reader section -->
     <string name="pref_hide_status_bar">Hide status bar</string>
@@ -168,9 +178,11 @@
     <string name="decode_image_error">The image could not be loaded.\nTry to change the image decoder</string>
 
     <!-- Library update service notifications -->
-    <string name="notification_progress">Update progress: %1$d/%2$d</string>
-    <string name="notification_completed">Update completed</string>
+    <string name="notification_update_progress">Update progress: %1$d/%2$d</string>
+    <string name="notification_update_completed">Update completed</string>
+    <string name="notification_update_error">An unexpected error occurred updating the library</string>
     <string name="notification_no_new_chapters">No new chapters found</string>
     <string name="notification_new_chapters">Found new chapters for:</string>
+    <string name="notification_manga_update_failed">Failed updating mangas:</string>
 
 </resources>

+ 13 - 0
app/src/main/res/xml/pref_general.xml

@@ -6,4 +6,17 @@
         android:persistent="false"
         android:title="@string/pref_library_columns"/>
 
+    <eu.kanade.mangafeed.ui.setting.preference.IntListPreference
+        android:key="@string/pref_library_update_interval_key"
+        android:title="@string/pref_library_update_interval"
+        android:entries="@array/library_update_interval"
+        android:entryValues="@array/library_update_interval_values"
+        android:defaultValue="0"
+        android:summary="%s"/>
+
+    <CheckBoxPreference
+        android:key="@string/pref_update_only_non_completed_key"
+        android:title="@string/pref_update_only_non_completed"
+        android:defaultValue="false"/>
+
 </PreferenceScreen>