diff --git a/Clover/app/src/main/AndroidManifest.xml b/Clover/app/src/main/AndroidManifest.xml
index d6a9ae7b33..3d54410518 100644
--- a/Clover/app/src/main/AndroidManifest.xml
+++ b/Clover/app/src/main/AndroidManifest.xml
@@ -88,6 +88,10 @@ along with this program. If not, see .
android:name=".ui.service.SavingNotification"
android:exported="false" />
+
+
diff --git a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java
index 2b5b82ebc6..db57772ea5 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/manager/WatchManager.java
@@ -17,15 +17,9 @@
*/
package org.floens.chan.core.manager;
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
import android.support.annotation.Nullable;
import org.floens.chan.Chan;
@@ -38,15 +32,17 @@
import org.floens.chan.core.model.orm.Loadable;
import org.floens.chan.core.model.orm.Pin;
import org.floens.chan.core.pool.ChanLoaderFactory;
+import org.floens.chan.core.repository.PageRepository;
import org.floens.chan.core.settings.ChanSettings;
+import org.floens.chan.core.site.Page;
import org.floens.chan.core.site.loader.ChanThreadLoader;
import org.floens.chan.ui.helper.PostHelper;
+import org.floens.chan.ui.service.LastPageNotification;
import org.floens.chan.ui.service.WatchNotifier;
import org.floens.chan.utils.Logger;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -59,7 +55,6 @@
import de.greenrobot.event.EventBus;
-import static org.floens.chan.Chan.inject;
import static org.floens.chan.utils.AndroidUtils.getAppContext;
/**
@@ -106,6 +101,7 @@ enum IntervalType {
private final DatabasePinManager databasePinManager;
private final ChanLoaderFactory chanLoaderFactory;
private final WakeManager wakeManager;
+ private final PageRepository pageRepository;
private IntervalType currentInterval = IntervalType.NONE;
@@ -114,11 +110,12 @@ enum IntervalType {
private Set waitingForPinWatchersForBackgroundUpdate;
@Inject
- public WatchManager(DatabaseManager databaseManager, ChanLoaderFactory chanLoaderFactory, WakeManager wakeManager) {
+ public WatchManager(DatabaseManager databaseManager, ChanLoaderFactory chanLoaderFactory, WakeManager wakeManager, PageRepository pageRepository) {
//retain local references to needed managers/factories/pins
this.databaseManager = databaseManager;
this.chanLoaderFactory = chanLoaderFactory;
this.wakeManager = wakeManager;
+ this.pageRepository = pageRepository;
databasePinManager = databaseManager.getDatabasePinManager();
pins = databaseManager.runTask(databasePinManager.getPins());
@@ -557,6 +554,7 @@ public class PinWatcher implements ChanThreadLoader.ChanLoaderCallback {
private final List quotes = new ArrayList<>();
private boolean wereNewQuotes = false;
private boolean wereNewPosts = false;
+ private boolean notified;
public PinWatcher(Pin pin) {
this.pin = pin;
@@ -605,6 +603,20 @@ private void destroy() {
private boolean update(boolean fromBackground) {
if (!pin.isError && pin.watching) {
+ if (ChanSettings.watchEnabled.get() && ChanSettings.watchLastPageNotify.get() && ChanSettings.watchBackground.get() && chanLoader.getThread() != null) {
+ //check last page stuff, fake a post
+ Page p = pageRepository.getPage(chanLoader.getThread().op);
+ if (p == null) {
+ Logger.w(TAG, "Pages for page not loaded yet, will check for notification next time");
+ } else if (p.page >= pin.loadable.board.pages && !notified) {
+ Intent pageNotifyIntent = new Intent(getAppContext(), LastPageNotification.class);
+ pageNotifyIntent.putExtra("pin_id", pin.id);
+ getAppContext().startService(pageNotifyIntent);
+ notified = true;
+ } else if (p.page < pin.loadable.board.pages) {
+ notified = false;
+ }
+ }
if (fromBackground) {
// Always load regardless of timer, since the time left is not accurate for 15min+ intervals
chanLoader.clearTimer();
diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java b/Clover/app/src/main/java/org/floens/chan/core/model/Post.java
index 3cbada5aa2..eddd3577e7 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/model/Post.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/model/Post.java
@@ -32,7 +32,7 @@
* Contains all data needed to represent a single post.
* All {@code final} fields are thread-safe.
*/
-public class Post {
+public class Post implements Comparable {
public final String boardId;
public final Board board;
@@ -108,6 +108,16 @@ public class Post {
private long lastModified;
private String title = "";
+ public int compareTo(Post p) {
+ if (this.time < p.time) {
+ return 1;
+ } else if (this.time > p.time) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
private Post(Builder builder) {
board = builder.board;
boardId = builder.board.code;
diff --git a/Clover/app/src/main/java/org/floens/chan/core/repository/PageRepository.java b/Clover/app/src/main/java/org/floens/chan/core/repository/PageRepository.java
index 656f884de8..d4aa06ea31 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/repository/PageRepository.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/repository/PageRepository.java
@@ -47,6 +47,9 @@ public PageRepository() {
}
public Page getPage(Post op) {
+ if(op == null) {
+ return null;
+ }
Pages pages = getPages(op.board);
if (pages == null) {
return null;
diff --git a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
index ba5f9cc9f1..79dd977944 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
@@ -140,6 +140,7 @@ public String getKey() {
public static final BooleanSetting watchCountdown;
public static final BooleanSetting watchBackground;
public static final BooleanSetting watchFilterPin;
+ public static final BooleanSetting watchLastPageNotify;
public static final IntegerSetting watchBackgroundInterval;
public static final StringSetting watchNotifyMode;
public static final StringSetting watchSound;
@@ -228,6 +229,7 @@ public String getKey() {
watchFilterPin = new BooleanSetting(p, "preference_watch_filter_pin", false);
watchFilterPin.addCallback(((setting, value) ->
EventBus.getDefault().post(new SettingChanged<>(watchFilterPin))));
+ watchLastPageNotify = new BooleanSetting(p, "preference_watch_last_page_notify", false);
watchBackgroundInterval = new IntegerSetting(p, "preference_watch_background_interval", WakeManager.BACKGROUND_INTERVAL);
watchBackgroundInterval.addCallback((setting, value) ->
EventBus.getDefault().post(new SettingChanged<>(watchBackgroundInterval)));
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
index e180620653..f5054f42e3 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/StartActivity.java
@@ -324,6 +324,34 @@ protected void onNewIntent(Intent intent) {
browseController.showThread(pin.loadable, false);
}
}
+ } else if (pinId != -2 && mainNavigationController.getTop() instanceof ThreadSlideController) {
+ if(pinId == -1) {
+ drawerController.onMenuClicked();
+ } else {
+ Pin pin = watchManager.findPinById(pinId);
+ if(pin != null) {
+ List controllers = mainNavigationController.childControllers;
+ for (Controller controller : controllers) {
+ if (controller instanceof ViewThreadController) {
+ ((ViewThreadController) controller).loadThread(pin.loadable);
+ break;
+ } else if (controller instanceof ThreadSlideController) {
+ ThreadSlideController slideNav = (ThreadSlideController) controller;
+ if (slideNav.getRightController() instanceof ViewThreadController) {
+ ((ViewThreadController) slideNav.getRightController()).loadThread(pin.loadable);
+ slideNav.switchToController(false);
+ break;
+ } else {
+ ViewThreadController v = new ViewThreadController(this);
+ v.setLoadable(pin.loadable);
+ slideNav.setRightController(v);
+ slideNav.switchToController(false);
+ break;
+ }
+ }
+ }
+ }
+ }
}
}
}
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java
index 3b8bc407bd..793397de91 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/WatchSettingsController.java
@@ -37,6 +37,7 @@ public class WatchSettingsController extends SettingsController implements Compo
private SettingView enableFilterPin;
private SettingView backgroundTimeout;
+ private SettingView lastPageNotifyMode;
private SettingView notifyMode;
private SettingView soundMode;
private SettingView peekMode;
@@ -71,6 +72,7 @@ public void onCreate() {
if (!ChanSettings.watchBackground.get()) {
setSettingViewVisibility(backgroundTimeout, false, false);
+ setSettingViewVisibility(lastPageNotifyMode, false, false);
setSettingViewVisibility(notifyMode, false, false);
setSettingViewVisibility(soundMode, false, false);
setSettingViewVisibility(peekMode, false, false);
@@ -92,6 +94,7 @@ public void onPreferenceChange(SettingView item) {
if (item == enableBackground) {
boolean enabled = ChanSettings.watchBackground.get();
setSettingViewVisibility(backgroundTimeout, enabled, true);
+ setSettingViewVisibility(lastPageNotifyMode, enabled, true);
setSettingViewVisibility(notifyMode, enabled, true);
setSettingViewVisibility(soundMode, enabled, true);
setSettingViewVisibility(peekMode, enabled, true);
@@ -129,6 +132,8 @@ public String getBottomDescription() {
}
});
+ lastPageNotifyMode = settings.add(new BooleanSettingView(this, ChanSettings.watchLastPageNotify, R.string.setting_thread_page_limit_notify, R.string.setting_thread_page_limit_notify_description));
+
notifyMode = settings.add(new ListSettingView<>(this, ChanSettings.watchNotifyMode, R.string.setting_watch_notify_mode,
context.getResources().getStringArray(R.array.setting_watch_notify_modes), new String[]{"all", "quotes"}));
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/service/LastPageNotification.java b/Clover/app/src/main/java/org/floens/chan/ui/service/LastPageNotification.java
new file mode 100644
index 0000000000..5c32ddef5e
--- /dev/null
+++ b/Clover/app/src/main/java/org/floens/chan/ui/service/LastPageNotification.java
@@ -0,0 +1,81 @@
+package org.floens.chan.ui.service;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.support.annotation.Nullable;
+import android.support.v4.app.NotificationCompat;
+import android.support.v4.app.NotificationManagerCompat;
+
+import org.floens.chan.R;
+import org.floens.chan.core.manager.WatchManager;
+import org.floens.chan.core.model.orm.Pin;
+import org.floens.chan.ui.activity.BoardActivity;
+
+import java.util.Random;
+
+import javax.inject.Inject;
+
+import static org.floens.chan.Chan.inject;
+import static org.floens.chan.utils.AndroidUtils.getAppContext;
+
+public class LastPageNotification extends Service {
+ //random notification ID's, so one notification per thread
+ private Random random = new Random();
+
+ @Inject
+ WatchManager watchManager;
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ inject(this);
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null && intent.getExtras() != null) {
+ Bundle extras = intent.getExtras();
+ int pinId = extras.getInt("pin_id");
+
+ //NotificationManagerCompat.from(getAppContext()).notify(random.nextInt(), getNotification(pinId));
+ ((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(random.nextInt(), getNotification(pinId));
+ }
+ return START_STICKY;
+ }
+
+ private Notification getNotification(int pinId) {
+ Pin pin = watchManager.findPinById(pinId);
+
+ Intent intent = new Intent(this, BoardActivity.class);
+ intent.setAction(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
+ .putExtra("pin_id", pinId);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, random.nextInt(), intent, PendingIntent.FLAG_ONE_SHOT);
+
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+ builder.setSmallIcon(R.drawable.ic_stat_notify_alert)
+ .setContentTitle(getString(R.string.thread_page_limit))
+ .setContentText(pin.loadable.title)
+ .setContentIntent(pendingIntent)
+ .setPriority(NotificationCompat.PRIORITY_MAX)
+ .setTimeoutAfter(10 * 1000 * 60)
+ .setAutoCancel(true);
+
+ return builder.build();
+ }
+}
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java b/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java
index dbc3eb7c21..3a8ffd7a94 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/service/WatchNotifier.java
@@ -48,7 +48,6 @@
public class WatchNotifier extends Service {
private static final String TAG = "WatchNotifier";
private static final int NOTIFICATION_ID = 1;
- private static final PostAgeComparator POST_AGE_COMPARATOR = new PostAgeComparator();
private static final int SUBJECT_LENGTH = 6;
private static final String IMAGE_TEXT = "(img) ";
private static final Pattern SHORTEN_NO_PATTERN = Pattern.compile(">>\\d+(?=\\d{3})(\\d{3})");
@@ -186,7 +185,7 @@ private Notification notifyAboutPosts(List pins, List subjectPins, Lis
}
}
- Collections.sort(postsForExpandedLines, POST_AGE_COMPARATOR);
+ Collections.sort(postsForExpandedLines);
List expandedLines = new ArrayList<>();
for (Post postForExpandedLine : postsForExpandedLines) {
CharSequence prefix;
@@ -288,17 +287,4 @@ private Notification get(String title, String smallText, List expa
return builder.build();
}
-
- private static class PostAgeComparator implements Comparator {
- @Override
- public int compare(Post lhs, Post rhs) {
- if (lhs.time < rhs.time) {
- return 1;
- } else if (lhs.time > rhs.time) {
- return -1;
- } else {
- return 0;
- }
- }
- }
}
diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml
index 39a49d164e..3a49157f4a 100644
--- a/Clover/app/src/main/res/values/strings.xml
+++ b/Clover/app/src/main/res/values/strings.xml
@@ -360,6 +360,8 @@ Enable \"Play videos with external player\" in the settings to play videos with
Saved as \"%1$s\"
Saving image failed
+ Thread hit last page
+
Setup sites
History
@@ -391,6 +393,8 @@ Enable \"Play videos with external player\" in the settings to play videos with
Pin posts that match filters with pinning enabled
Background update interval
The interval between updates when placed in the background
+ Last page notifications
+ Notify when threads hit the last page
Notify about
- All posts