arg) {
return stat.url();
}
+ @Override
+ public HttpUrl pages(Board board) {
+ return root.builder().s(board.code).s("threads.json").url();
+ }
+
@Override
public HttpUrl reply(Loadable loadable) {
return sys.builder().s("post.php").url();
diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/loader/ChanThreadLoader.java b/Clover/app/src/main/java/org/floens/chan/core/site/loader/ChanThreadLoader.java
index a197639d42..f502d9aeb9 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/site/loader/ChanThreadLoader.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/site/loader/ChanThreadLoader.java
@@ -27,6 +27,9 @@
import org.floens.chan.core.model.ChanThread;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.orm.Loadable;
+import org.floens.chan.core.site.Page;
+import org.floens.chan.core.site.Pages;
+import org.floens.chan.core.site.SiteActions;
import org.floens.chan.core.site.parser.ChanReader;
import org.floens.chan.core.site.parser.ChanReaderRequest;
import org.floens.chan.ui.helper.PostHelper;
@@ -52,7 +55,7 @@
* {@link ChanLoaderCallback}.
* For threads timers can be started with {@link #setTimer()} to do a request later.
*/
-public class ChanThreadLoader implements Response.ErrorListener, Response.Listener {
+public class ChanThreadLoader implements Response.ErrorListener, Response.Listener, SiteActions.PagesListener {
private static final String TAG = "ChanThreadLoader";
private static final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
@@ -72,6 +75,9 @@ public class ChanThreadLoader implements Response.ErrorListener, Response.Listen
private long lastLoadTime;
private ScheduledFuture> pendingFuture;
+ private boolean requestedPages = false;
+ private Pages pages;
+
/**
* Do not call this constructor yourself, obtain ChanLoaders through {@link org.floens.chan.core.pool.ChanLoaderFactory}
*/
@@ -245,6 +251,11 @@ private ChanLoaderRequest getData() {
volleyRequestQueue.add(request.getVolleyRequest());
+ if(!requestedPages) {
+ loadable.site.actions().pages(loadable.board, this);
+ requestedPages = true;
+ }
+
return request;
}
@@ -340,6 +351,16 @@ private void clearPendingRunnable() {
}
}
+ @Override
+ public void onPagesReceived(Pages pages) {
+ this.pages = pages;
+ requestedPages = false;
+ }
+
+ public Pages getPages() {
+ return pages;
+ }
+
public interface ChanLoaderCallback {
void onChanLoaderData(ChanThread result);
diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
index fc4a3ed349..288951edec 100644
--- a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
+++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4.java
@@ -30,6 +30,8 @@
import org.floens.chan.core.settings.SharedPreferencesSettingProvider;
import org.floens.chan.core.settings.StringSetting;
import org.floens.chan.core.site.Boards;
+import org.floens.chan.core.site.Page;
+import org.floens.chan.core.site.Pages;
import org.floens.chan.core.site.Site;
import org.floens.chan.core.site.SiteActions;
import org.floens.chan.core.site.SiteAuthentication;
@@ -253,6 +255,14 @@ public HttpUrl boards() {
.build();
}
+ @Override
+ public HttpUrl pages(Board board) {
+ return a.newBuilder()
+ .addPathSegment(board.code)
+ .addPathSegment("threads.json")
+ .build();
+ }
+
@Override
public HttpUrl archive(Board board) {
return b.newBuilder()
@@ -345,6 +355,16 @@ public void boards(final BoardsListener listener) {
}));
}
+ @Override
+ public void pages(Board board, PagesListener listener) {
+ requestQueue.add(new Chan4PagesRequest(Chan4.this, board, response -> {
+ listener.onPagesReceived(new Pages(response));
+ }, (error) -> {
+ Logger.e(TAG, "Failed to get threads for board " + board.code);
+ listener.onPagesReceived(new Pages(new ArrayList()));
+ }));
+ }
+
@Override
public void archive(Board board, ArchiveListener archiveListener) {
requestQueue.add(new Chan4ArchiveRequest(Chan4.this, board,
diff --git a/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4PagesRequest.java b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4PagesRequest.java
new file mode 100644
index 0000000000..8b7bfb3745
--- /dev/null
+++ b/Clover/app/src/main/java/org/floens/chan/core/site/sites/chan4/Chan4PagesRequest.java
@@ -0,0 +1,104 @@
+/*
+ * Clover - 4chan browser https://github.com/Floens/Clover/
+ * Copyright (C) 2014 Floens
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.floens.chan.core.site.sites.chan4;
+
+import android.util.JsonReader;
+
+import com.android.volley.Response.ErrorListener;
+import com.android.volley.Response.Listener;
+
+import org.floens.chan.core.model.orm.Board;
+import org.floens.chan.core.net.JsonReaderRequest;
+import org.floens.chan.core.site.Page;
+import org.floens.chan.core.site.Site;
+import org.floens.chan.core.site.ThreadTime;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Chan4PagesRequest extends JsonReaderRequest> {
+
+ public Chan4PagesRequest(Site site, Board board, Listener> listener, ErrorListener errorListener) {
+ super(site.endpoints().pages(board).toString(), listener, errorListener);
+ }
+
+ @Override
+ public List readJson(JsonReader reader) throws Exception {
+ List pages = new ArrayList<>();
+
+ reader.beginArray();
+ while (reader.hasNext()) {
+ pages.add(readPageEntry(reader));
+ }
+ reader.endArray();
+
+ return pages;
+ }
+
+ private Page readPageEntry(JsonReader reader) throws Exception {
+ int pageNo = -1;
+ List threadTimes = null;
+
+ reader.beginObject();
+ while(reader.hasNext()) {
+ String nextName = reader.nextName();
+ if(nextName.equals("page")) {
+ pageNo = reader.nextInt();
+ } else if (nextName.equals("threads")) {
+ threadTimes = readThreadTimes(reader);
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+
+ return new Page(pageNo, threadTimes);
+ }
+
+ private List readThreadTimes(JsonReader reader) throws Exception {
+ List threadTimes = new ArrayList<>();
+
+ reader.beginArray();
+ while(reader.hasNext()) {
+ threadTimes.add(readThreadTime(reader));
+ }
+ reader.endArray();
+
+ return threadTimes;
+ }
+
+ private ThreadTime readThreadTime(JsonReader reader) throws Exception {
+ int no = -1;
+ long modified = -1;
+
+ reader.beginObject();
+ while(reader.hasNext()) {
+ String nextName = reader.nextName();
+ if (nextName.equals("no")) {
+ no = reader.nextInt();
+ } else if (nextName.equals("last_modified")) {
+ modified = reader.nextLong();
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+
+ return new ThreadTime(no, modified);
+ }
+}
diff --git a/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java b/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java
index c681865bb5..c8915849c8 100644
--- a/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java
+++ b/Clover/app/src/main/java/org/floens/chan/ui/cell/ThreadStatusCell.java
@@ -33,6 +33,7 @@
import org.floens.chan.core.model.ChanThread;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.orm.Board;
+import org.floens.chan.core.site.Page;
import static org.floens.chan.utils.AndroidUtils.ROBOTO_MEDIUM;
@@ -147,6 +148,18 @@ public boolean update() {
String ips = op.getUniqueIps() + "P";
finalText = TextUtils.concat(finalText, " / " + ips);
}
+
+ Page p = callback.getPage(op);
+ SpannableString page;
+ if(p != null) {
+ page = new SpannableString(String.valueOf(p.page));
+ if (p.page > board.pages) {
+ page.setSpan(new StyleSpan(Typeface.ITALIC), 0, page.length(), 0);
+ }
+ } else {
+ page = new SpannableString("?");
+ }
+ finalText = TextUtils.concat(finalText, " / " + getContext().getString(R.string.thread_page_no) + " " + page);
}
}
@@ -206,6 +219,8 @@ public interface Callback {
ChanThread getChanThread();
+ Page getPage(Post op);
+
void onListStatusClicked();
}
}
diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml
index d60021d41e..2cb5e64453 100644
--- a/Clover/app/src/main/res/values/strings.xml
+++ b/Clover/app/src/main/res/values/strings.xml
@@ -149,6 +149,7 @@ Re-enable this permission in the app settings if you permanently disabled it."
Retry
Archived
Closed
+ Page
- %d new post
- %d new posts