diff --git a/Chan/res/drawable/pin_icon.xml b/Chan/res/drawable/pin_icon_blue.xml
similarity index 100%
rename from Chan/res/drawable/pin_icon.xml
rename to Chan/res/drawable/pin_icon_blue.xml
diff --git a/Chan/res/drawable/pin_icon_red.xml b/Chan/res/drawable/pin_icon_red.xml
new file mode 100644
index 00000000..c12eb1e2
--- /dev/null
+++ b/Chan/res/drawable/pin_icon_red.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/Chan/res/layout/pin_item.xml b/Chan/res/layout/pin_item.xml
index 33b85c79..5d9b751e 100644
--- a/Chan/res/layout/pin_item.xml
+++ b/Chan/res/layout/pin_item.xml
@@ -23,7 +23,8 @@
@@ -34,7 +35,7 @@
android:gravity="center"
android:textSize="16dp"
android:textColor="#fff"
- android:text="99+" />
+ android:text="99" />
diff --git a/Chan/src/org/floens/chan/activity/BaseActivity.java b/Chan/src/org/floens/chan/activity/BaseActivity.java
index 31ee912b..742b5ec2 100644
--- a/Chan/src/org/floens/chan/activity/BaseActivity.java
+++ b/Chan/src/org/floens/chan/activity/BaseActivity.java
@@ -36,7 +36,7 @@ import android.widget.EditText;
import android.widget.ListView;
import android.widget.ShareActionProvider;
-public abstract class BaseActivity extends Activity implements PanelSlideListener {
+public abstract class BaseActivity extends Activity implements PanelSlideListener, PinnedManager.PinListener {
private final static int ACTION_OPEN_URL = 1;
protected PinnedAdapter pinnedAdapter;
@@ -71,6 +71,15 @@ public abstract class BaseActivity extends Activity implements PanelSlideListene
threadPane = (SlidingPaneLayout) findViewById(R.id.pane_container);
initPane();
+
+ PinnedManager.getInstance().addPinListener(this);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+
+ PinnedManager.getInstance().removePinListener(this);
}
protected void initDrawer() {
@@ -134,6 +143,11 @@ public abstract class BaseActivity extends Activity implements PanelSlideListene
threadPane.openPane();
}
+ @Override
+ public void onPinsChanged() {
+ pinnedAdapter.notifyDataSetChanged();
+ }
+
public void addPin(Pin pin) {
if (PinnedManager.getInstance().add(pin)) {
pinnedAdapter.add(pin);
diff --git a/Chan/src/org/floens/chan/adapter/PinnedAdapter.java b/Chan/src/org/floens/chan/adapter/PinnedAdapter.java
index 17d5c1f1..0ea8b011 100644
--- a/Chan/src/org/floens/chan/adapter/PinnedAdapter.java
+++ b/Chan/src/org/floens/chan/adapter/PinnedAdapter.java
@@ -11,6 +11,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
+import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -45,6 +46,18 @@ public class PinnedAdapter extends ArrayAdapter {
view = (LinearLayout) inflater.inflate(R.layout.pin_item, null);
((TextView) view.findViewById(R.id.drawer_item_text)).setText(item.loadable.title);
+
+ int count = Math.max(0, item.watchNewCount - item.watchLastCount);
+ String total = Integer.toString(Math.min(count, 999));
+
+ ((TextView) view.findViewById(R.id.drawer_item_count)).setText(total);
+
+ FrameLayout frameLayout = (FrameLayout) view.findViewById(R.id.drawer_item_count_container);
+// if (Math.random() < 0.5d) {
+ frameLayout.setBackgroundResource(R.drawable.pin_icon_blue);
+// } else {
+// frameLayout.setBackgroundResource(R.drawable.pin_icon_red);
+// }
}
if (listener != null) {
diff --git a/Chan/src/org/floens/chan/database/DatabaseHelper.java b/Chan/src/org/floens/chan/database/DatabaseHelper.java
index 6decdf0a..9c45038c 100644
--- a/Chan/src/org/floens/chan/database/DatabaseHelper.java
+++ b/Chan/src/org/floens/chan/database/DatabaseHelper.java
@@ -16,7 +16,7 @@ import com.j256.ormlite.table.TableUtils;
public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String DATABASE_NAME = "ChanDB";
- private static final int DATABASE_VERSION = 1;
+ private static final int DATABASE_VERSION = 3;
public Dao pinDao;
public Dao loadableDao;
@@ -48,6 +48,16 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
switch(oldVersion) {
// Change tables if we make adjustments
}
+
+ // Drop the tables and recreate them for now
+ try {
+ TableUtils.dropTable(connectionSource, Pin.class, true);
+ TableUtils.dropTable(connectionSource, Loadable.class, true);
+
+ onCreate(database, connectionSource);
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
}
}
diff --git a/Chan/src/org/floens/chan/fragment/ThreadFragment.java b/Chan/src/org/floens/chan/fragment/ThreadFragment.java
index b3dd1f97..14c11542 100644
--- a/Chan/src/org/floens/chan/fragment/ThreadFragment.java
+++ b/Chan/src/org/floens/chan/fragment/ThreadFragment.java
@@ -81,6 +81,7 @@ public class ThreadFragment extends Fragment implements ThreadListener {
stopLoading();
this.loadable = loadable;
+
threadManager.startLoading(loadable);
}
diff --git a/Chan/src/org/floens/chan/manager/PinnedManager.java b/Chan/src/org/floens/chan/manager/PinnedManager.java
index a3bbca15..10ef76b3 100644
--- a/Chan/src/org/floens/chan/manager/PinnedManager.java
+++ b/Chan/src/org/floens/chan/manager/PinnedManager.java
@@ -1,5 +1,6 @@
package org.floens.chan.manager;
+import java.util.ArrayList;
import java.util.List;
import org.floens.chan.adapter.PinnedAdapter;
@@ -13,6 +14,7 @@ public class PinnedManager {
private static PinnedManager instance;
private final Context context;
+ private final List listeners = new ArrayList();
private final List pins;
public PinnedManager(Context context) {
@@ -26,6 +28,14 @@ public class PinnedManager {
return instance;
}
+ public void addPinListener(PinListener l) {
+ listeners.add(l);
+ }
+
+ public void removePinListener(PinListener l) {
+ listeners.remove(l);
+ }
+
public PinnedAdapter getAdapter() {
PinnedAdapter adapter = new PinnedAdapter(context, 0);
@@ -72,6 +82,9 @@ public class PinnedManager {
pins.add(pin);
DatabaseManager.getInstance().addPin(pin);
+
+ onPinsChanged();
+
return true;
}
@@ -82,6 +95,8 @@ public class PinnedManager {
public void remove(Pin pin) {
pins.remove(pin);
DatabaseManager.getInstance().removePin(pin);
+
+ onPinsChanged();
}
/**
@@ -90,6 +105,8 @@ public class PinnedManager {
*/
public void update(Pin pin) {
DatabaseManager.getInstance().updatePin(pin);
+
+ onPinsChanged();
}
/**
@@ -105,6 +122,22 @@ public class PinnedManager {
}
}).start();
}
+
+ public void onPinViewed(Pin pin) {
+ pin.watchLastCount = pin.watchNewCount;
+
+ onPinsChanged();
+ }
+
+ public void onPinsChanged() {
+ for (PinListener l : listeners) {
+ l.onPinsChanged();
+ }
+ }
+
+ public static interface PinListener {
+ public void onPinsChanged();
+ }
}
diff --git a/Chan/src/org/floens/chan/manager/ThreadManager.java b/Chan/src/org/floens/chan/manager/ThreadManager.java
index 92b264dc..e75e9c56 100644
--- a/Chan/src/org/floens/chan/manager/ThreadManager.java
+++ b/Chan/src/org/floens/chan/manager/ThreadManager.java
@@ -8,6 +8,7 @@ import org.floens.chan.activity.ReplyActivity;
import org.floens.chan.fragment.PostRepliesFragment;
import org.floens.chan.fragment.ReplyFragment;
import org.floens.chan.model.Loadable;
+import org.floens.chan.model.Pin;
import org.floens.chan.model.Post;
import org.floens.chan.model.PostLinkable;
import org.floens.chan.net.ThreadLoader;
@@ -35,9 +36,10 @@ import com.android.volley.VolleyError;
/**
* All PostView's need to have this referenced.
- * This manages some things like pages, starting and stopping of loading etc.
+ * This manages some things like pages, starting and stopping of loading,
+ * handling linkables, replies popups etc.
*/
-public class ThreadManager {
+public class ThreadManager implements ThreadLoader.ThreadLoaderListener {
private final Activity activity;
private final ThreadLoader threadLoader;
private final ThreadManager.ThreadListener threadListener;
@@ -51,17 +53,17 @@ public class ThreadManager {
this.activity = context;
threadListener = listener;
- threadLoader = new ThreadLoader(new ThreadLoader.ThreadLoaderListener() {
- @Override
- public void onError(VolleyError error) {
- listener.onThreadLoadError(error);
- }
-
- @Override
- public void onData(List result) {
- listener.onThreadLoaded(result);
- }
- });
+ threadLoader = new ThreadLoader(this);
+ }
+
+ @Override
+ public void onError(VolleyError error) {
+ threadListener.onThreadLoadError(error);
+ }
+
+ @Override
+ public void onData(List result) {
+ threadListener.onThreadLoaded(result);
}
public boolean hasThread() {
@@ -80,6 +82,11 @@ public class ThreadManager {
this.loadable = loadable;
threadLoader.start(loadable);
+
+ Pin pin = PinnedManager.getInstance().findPinByLoadable(loadable);
+ if (pin != null) {
+ PinnedManager.getInstance().onPinViewed(pin);
+ }
}
public void stop() {
diff --git a/Chan/src/org/floens/chan/model/Loadable.java b/Chan/src/org/floens/chan/model/Loadable.java
index 75136652..48b2e270 100644
--- a/Chan/src/org/floens/chan/model/Loadable.java
+++ b/Chan/src/org/floens/chan/model/Loadable.java
@@ -32,6 +32,12 @@ public class Loadable {
@DatabaseField
public int listViewTop;
+ /**
+ * When simple mode is enabled, CPU intensive methods won't get called.
+ * This is used for the thread watcher.
+ */
+ public boolean simpleMode = false;
+
/**
* Constructs an empty loadable.
* The mode is INVALID.
@@ -120,6 +126,19 @@ public class Loadable {
bundle.putInt(p + ".listViewTop", listViewTop);
}
+ public Loadable copy() {
+ Loadable copy = new Loadable();
+ copy.mode = mode;
+ copy.board = board;
+ copy.no = no;
+ copy.title = title;
+ copy.listViewIndex = listViewIndex;
+ copy.listViewTop = listViewTop;
+ copy.simpleMode = simpleMode;
+
+ return copy;
+ }
+
public static class Mode {
public static final int INVALID = -1;
public static final int THREAD = 0;
diff --git a/Chan/src/org/floens/chan/model/Pin.java b/Chan/src/org/floens/chan/model/Pin.java
index 548a6dc0..d38ea88b 100644
--- a/Chan/src/org/floens/chan/model/Pin.java
+++ b/Chan/src/org/floens/chan/model/Pin.java
@@ -1,16 +1,12 @@
package org.floens.chan.model;
-import java.util.List;
+import org.floens.chan.watch.PinWatcher;
-import org.floens.chan.net.ThreadLoader;
-import org.floens.chan.utils.Logger;
-
-import com.android.volley.VolleyError;
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@DatabaseTable
-public class Pin implements ThreadLoader.ThreadLoaderListener {
+public class Pin {
// Database stuff
@DatabaseField(generatedId = true)
private int id;
@@ -27,35 +23,22 @@ public class Pin implements ThreadLoader.ThreadLoaderListener {
};
// PinnedService stuff
- public ThreadLoader threadLoader;
- public int lastPostCount;
- public int newPostCount;
+ public PinWatcher pinWatcher;
- public void update() {
- Logger.test("Update in pin");
-
- if (threadLoader == null) {
- threadLoader = new ThreadLoader(this);
- }
-
- threadLoader.start(loadable);
- }
+ @DatabaseField
+ public int watchLastCount;
- @Override
- public void onError(VolleyError error) {
- Logger.test("OnError in pin: ", error);
- }
+ @DatabaseField
+ public int watchNewCount;
- @Override
- public void onData(List result) {
- Logger.test("OnData in pin: ");
- Logger.test("Size: " + result.size());
+ public void updateWatch() {
+ if (pinWatcher == null) {
+ pinWatcher = new PinWatcher(this);
+ }
- newPostCount = result.size();
+ pinWatcher.update();
}
}
-
-
diff --git a/Chan/src/org/floens/chan/model/Post.java b/Chan/src/org/floens/chan/model/Post.java
index 78a18d36..daab99e5 100644
--- a/Chan/src/org/floens/chan/model/Post.java
+++ b/Chan/src/org/floens/chan/model/Post.java
@@ -86,7 +86,7 @@ public class Post {
* Finish up the data
* @return false if this data is invalid
*/
- public boolean finish() {
+ public boolean finish(Loadable loadable) {
if (board == null) return false;
if (no < 0 || resto < 0 || date == null) return false;
@@ -105,7 +105,7 @@ public class Post {
}
if (rawComment != null) {
- comment = parseComment(rawComment);
+ comment = parseComment(rawComment, loadable.simpleMode);
}
try {
@@ -123,9 +123,13 @@ public class Post {
return true;
}
- private CharSequence parseComment(String commentRaw) {
- CharSequence total = new SpannableString("");
+ private CharSequence parseComment(String commentRaw, boolean simpleMode) {
+ if (simpleMode) {
+ return "";
+ }
+ CharSequence total = new SpannableString("");
+
try {
String comment = commentRaw.replace("", "");
diff --git a/Chan/src/org/floens/chan/net/ChanReaderRequest.java b/Chan/src/org/floens/chan/net/ChanReaderRequest.java
index 90844f3e..bccf73da 100644
--- a/Chan/src/org/floens/chan/net/ChanReaderRequest.java
+++ b/Chan/src/org/floens/chan/net/ChanReaderRequest.java
@@ -2,6 +2,7 @@ package org.floens.chan.net;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
import org.floens.chan.model.Loadable;
import org.floens.chan.model.Post;
@@ -13,10 +14,10 @@ import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.extra.JsonReaderRequest;
-public class ChanReaderRequest extends JsonReaderRequest> {
+public class ChanReaderRequest extends JsonReaderRequest> {
private Loadable loadable;
- private ChanReaderRequest(String url, Listener> listener, ErrorListener errorListener) {
+ private ChanReaderRequest(String url, Listener> listener, ErrorListener errorListener) {
super(url, listener, errorListener);
}
@@ -29,7 +30,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
* @param errorListener
* @return New instance of ChanReaderRequest
*/
- public static ChanReaderRequest newInstance(Loadable loadable, Listener> listener, ErrorListener errorListener) {
+ public static ChanReaderRequest newInstance(Loadable loadable, Listener> listener, ErrorListener errorListener) {
String url;
if (loadable.isBoardMode()) {
@@ -54,19 +55,35 @@ public class ChanReaderRequest extends JsonReaderRequest> {
}
@Override
- public ArrayList readJson(JsonReader reader) {
+ public List readJson(JsonReader reader) {
+ List list = new ArrayList();
+
if (loadable.isBoardMode()) {
- return loadBoard(reader);
+ list = loadBoard(reader);
} else if (loadable.isThreadMode()) {
- return loadThread(reader);
+ list = loadThread(reader);
} else if (loadable.isCatalogMode()) {
- return loadCatalog(reader);
+ list = loadCatalog(reader);
} else {
throw new IllegalArgumentException("Unknown mode");
}
+
+ processPosts(list);
+
+ return list;
+ }
+
+ private void processPosts(List posts) {
+ for (Post post : posts) {
+ for (Post other : posts) {
+ if (other.repliesTo.contains(post.no)) {
+ post.repliesFrom.add(other.no);
+ }
+ }
+ }
}
- private ArrayList loadThread(JsonReader reader) {
+ private List loadThread(JsonReader reader) {
ArrayList list = new ArrayList();
try {
@@ -78,7 +95,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
// Thread array
while (reader.hasNext()) {
// Thread object
- list.add(readPostObject(reader, loadable.board));
+ list.add(readPostObject(reader));
}
reader.endArray();
} else {
@@ -100,7 +117,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
return list;
}
- private ArrayList loadBoard(JsonReader reader) {
+ private List loadBoard(JsonReader reader) {
ArrayList list = new ArrayList();
try {
@@ -115,7 +132,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
if (reader.nextName().equals("posts")) {
reader.beginArray();
- list.add(readPostObject(reader, loadable.board));
+ list.add(readPostObject(reader));
// Only consume one post
while (reader.hasNext()) reader.skipValue();
@@ -148,7 +165,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
return list;
}
- private ArrayList loadCatalog(JsonReader reader) {
+ private List loadCatalog(JsonReader reader) {
ArrayList list = new ArrayList();
try {
@@ -162,7 +179,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
reader.beginArray(); // Threads array
while (reader.hasNext()) {
- list.add(readPostObject(reader, loadable.board));
+ list.add(readPostObject(reader));
}
reader.endArray();
@@ -189,9 +206,9 @@ public class ChanReaderRequest extends JsonReaderRequest> {
return list;
}
- private Post readPostObject(JsonReader reader, String board) throws IllegalStateException, NumberFormatException, IOException {
+ private Post readPostObject(JsonReader reader) throws IllegalStateException, NumberFormatException, IOException {
Post post = new Post();
- post.board = board;
+ post.board = loadable.board;
reader.beginObject();
while(reader.hasNext()) {
@@ -252,7 +269,7 @@ public class ChanReaderRequest extends JsonReaderRequest> {
}
reader.endObject();
- if (!post.finish()) {
+ if (!post.finish(loadable)) {
throw new IOException("Incorrect data about post received.");
}
diff --git a/Chan/src/org/floens/chan/net/ThreadLoader.java b/Chan/src/org/floens/chan/net/ThreadLoader.java
index 21c13f28..7f7ffd29 100644
--- a/Chan/src/org/floens/chan/net/ThreadLoader.java
+++ b/Chan/src/org/floens/chan/net/ThreadLoader.java
@@ -1,6 +1,5 @@
package org.floens.chan.net;
-import java.util.ArrayList;
import java.util.List;
import org.floens.chan.ChanApplication;
@@ -65,9 +64,9 @@ public class ThreadLoader {
}
private ChanReaderRequest getData(Loadable loadable) {
- ChanReaderRequest request = ChanReaderRequest.newInstance(loadable, new Response.Listener>() {
+ ChanReaderRequest request = ChanReaderRequest.newInstance(loadable, new Response.Listener>() {
@Override
- public void onResponse(ArrayList list) {
+ public void onResponse(List list) {
loading = false;
onData(list);
}
@@ -88,7 +87,9 @@ public class ThreadLoader {
private void onData(List result) {
if (stopped) return;
- processPosts(result);
+ for (Post post : result) {
+ postsById.append(post.no, post);
+ }
listener.onData(result);
}
@@ -106,18 +107,6 @@ public class ThreadLoader {
listener.onError(error);
}
- private void processPosts(List posts) {
- for (Post post : posts) {
- postsById.append(post.no, post);
-
- for (Post other : posts) {
- if (other.repliesTo.contains(post.no)) {
- post.repliesFrom.add(other.no);
- }
- }
- }
- }
-
public static abstract interface ThreadLoaderListener {
public abstract void onData(List result);
public abstract void onError(VolleyError error);
diff --git a/Chan/src/org/floens/chan/service/PinnedService.java b/Chan/src/org/floens/chan/service/PinnedService.java
index f071da4c..ccdffb4d 100644
--- a/Chan/src/org/floens/chan/service/PinnedService.java
+++ b/Chan/src/org/floens/chan/service/PinnedService.java
@@ -10,7 +10,9 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
public class PinnedService extends Service {
private Thread loadThread;
@@ -61,10 +63,20 @@ public class PinnedService extends Service {
private void doUpdates() {
List pins = PinnedManager.getInstance().getPins();
for (Pin pin : pins) {
-// pin.update();
+ pin.updateWatch();
+// pin.newPostCount++;
}
}
+ public static void callOnPinsChanged() {
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ PinnedManager.getInstance().onPinsChanged();
+ }
+ });
+ }
+
@SuppressWarnings("deprecation")
private void showNotification(String text) {
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
diff --git a/Chan/src/org/floens/chan/watch/PinWatcher.java b/Chan/src/org/floens/chan/watch/PinWatcher.java
new file mode 100644
index 00000000..152d2ad4
--- /dev/null
+++ b/Chan/src/org/floens/chan/watch/PinWatcher.java
@@ -0,0 +1,61 @@
+package org.floens.chan.watch;
+
+import java.util.List;
+
+import org.floens.chan.model.Loadable;
+import org.floens.chan.model.Pin;
+import org.floens.chan.model.Post;
+import org.floens.chan.net.ThreadLoader;
+import org.floens.chan.service.PinnedService;
+import org.floens.chan.utils.Logger;
+
+import com.android.volley.VolleyError;
+
+public class PinWatcher implements ThreadLoader.ThreadLoaderListener {
+ private static final int[] timeouts = {10, 15, 20, 30, 60, 90, 120, 180, 240, 300};
+
+ private final ThreadLoader watchLoader;
+ private final Loadable watchLoadable;
+
+ private final Pin pin;
+
+ private long startTime;
+
+ public PinWatcher(Pin pin) {
+ this.pin = pin;
+
+ watchLoadable = pin.loadable.copy();
+ watchLoadable.simpleMode = true;
+
+ watchLoader = new ThreadLoader(this);
+ }
+
+ public void update() {
+ Logger.test("PinWatcher update");
+
+ startTime = System.currentTimeMillis();
+
+ watchLoader.start(watchLoadable);
+ }
+
+ @Override
+ public void onError(VolleyError error) {
+ Logger.test("PinWatcher onError: ", error);
+ }
+
+ @Override
+ public void onData(List result) {
+ int count = result.size();
+
+ Logger.i("PinWatcher onData");
+ Logger.i("Post size: " + count);
+
+ pin.watchNewCount = count;
+
+ Logger.i("Load time: " + (System.currentTimeMillis() - startTime) + "ms");
+
+ PinnedService.callOnPinsChanged();
+ }
+
+
+}