Refactored BoardManager and BoardEditor to use the database.

Added autofill to the add board dialog.
Allow unknown boards.
This to easy for users
captchafix
Florens Douwes 11 years ago
parent 5d4da74365
commit bb8bfe7984
  1. 1
      Chan/AndroidManifest.xml
  2. 7
      Chan/res/values/strings.xml
  3. 2
      Chan/src/org/floens/chan/ChanApplication.java
  4. 5
      Chan/src/org/floens/chan/core/loader/Loader.java
  5. 257
      Chan/src/org/floens/chan/core/manager/BoardManager.java
  6. 34
      Chan/src/org/floens/chan/core/model/Board.java
  7. 11
      Chan/src/org/floens/chan/core/net/BoardsRequest.java
  8. 9
      Chan/src/org/floens/chan/database/DatabaseHelper.java
  9. 51
      Chan/src/org/floens/chan/database/DatabaseManager.java
  10. 14
      Chan/src/org/floens/chan/ui/activity/BaseActivity.java
  11. 17
      Chan/src/org/floens/chan/ui/activity/BoardActivity.java
  12. 286
      Chan/src/org/floens/chan/ui/activity/BoardEditor.java
  13. 5
      Chan/src/org/floens/chan/ui/adapter/PostAdapter.java
  14. 8
      Chan/src/org/floens/chan/ui/view/DynamicListView.java
  15. 3
      Chan/src/org/floens/chan/ui/view/PostView.java
  16. 11
      Chan/src/org/floens/chan/utils/Time.java
  17. 15
      Chan/src/org/floens/chan/utils/Utils.java

@ -94,6 +94,7 @@
<activity
android:name="org.floens.chan.ui.activity.BoardEditor"
android:label="@string/board_edit"
android:configChanges="keyboardHidden|orientation|screenSize"
android:parentActivityName="org.floens.chan.ui.activity.BoardActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"

@ -42,9 +42,10 @@
<string name="board_edit">Edit my boards</string>
<string name="board_add">Add board</string>
<string name="board_add_fail">Unknown board code</string>
<string name="board_add_success">Added</string>
<string name="board_add_duplicate">You already have that board</string>
<string name="board_add_success">Added board</string>
<string name="board_add_duplicate">Board already added</string>
<string name="board_add_unknown_title">Unknown board code</string>
<string name="board_add_unknown">The board with code CODE is not know. Press OK to add it anyway.</string>
<string name="drawer_open">Open drawer</string>
<string name="drawer_close">Close drawer</string>

@ -95,7 +95,7 @@ public class ChanApplication extends Application implements PinListener {
imageLoader = new ImageLoader(volleyRequestQueue, new BitmapLruImageCache(1024 * 1024 * 8));
databaseManager = new DatabaseManager(this);
boardManager = new BoardManager(this);
boardManager = new BoardManager();
pinnedManager = new PinnedManager(this);
pinnedManager.addPinListener(this);
replyManager = new ReplyManager(this);

@ -8,6 +8,7 @@ import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.net.ChanReaderRequest;
import org.floens.chan.utils.Logger;
import org.floens.chan.utils.Time;
import android.os.Handler;
import android.os.Looper;
@ -173,7 +174,7 @@ public class Loader {
return 0L;
} else {
long waitTime = watchTimeouts[currentTimeout] * 1000L;
return lastLoadTime + waitTime - System.currentTimeMillis();
return lastLoadTime + waitTime - Time.get();
}
}
@ -263,7 +264,7 @@ public class Loader {
l.onData(result, loadable.isBoardMode());
}
lastLoadTime = System.currentTimeMillis();
lastLoadTime = Time.get();
if (loadable.isThreadMode()) {
setTimer(result.size());

@ -1,111 +1,66 @@
package org.floens.chan.core.manager;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.chan.ChanUrls;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.net.BoardsRequest;
import org.floens.chan.utils.Logger;
import android.content.Context;
import android.widget.Toast;
import org.floens.chan.utils.Time;
import com.android.volley.Response;
import com.android.volley.VolleyError;
public class BoardManager {
private static final String TAG = "BoardManager";
private static final Comparator<Board> savedOrder = new Comparator<Board>() {
@Override
public int compare(Board lhs, Board rhs) {
return lhs.order < rhs.order ? -1 : 1;
}
};
private final Context context;
// Including nsfw ones
private ArrayList<Board> allBoards = new ArrayList<Board>();
private ArrayList<Board> myBoards = new ArrayList<Board>();
private final ArrayList<String> myBoardsKeys = new ArrayList<String>();
private final ArrayList<String> myBoardsValues = new ArrayList<String>();
private List<Board> allBoards;
public BoardManager(Context context) {
this.context = context;
private final List<String> savedKeys = new ArrayList<String>();
private final List<String> savedValues = new ArrayList<String>();
public BoardManager() {
loadBoards();
loadFromServer();
myBoards = loadMyBoards();
updateMyBoardsKeysAndValues(myBoards);
}
/**
* Avoid having 0 boards, which causes graphical problems
*
* @param list
*/
private ArrayList<Board> getDefaultBoards() {
ArrayList<Board> list = new ArrayList<Board>();
{
Board board = new Board();
board.key = "Video Games";
board.value = "v";
list.add(board);
}
{
Board board = new Board();
board.key = "Anime & Manga";
board.value = "a";
list.add(board);
}
{
Board board = new Board();
board.key = "Comics & Cartoons";
board.value = "co";
list.add(board);
}
{
Board board = new Board();
board.key = "Health & Fitness";
board.value = "fit";
list.add(board);
}
{
Board board = new Board();
board.key = "Technology";
board.value = "g";
list.add(board);
}
return list;
}
public ArrayList<Board> getMyBoards() {
return myBoards;
}
public void setMyBoards(ArrayList<Board> list) {
myBoards.clear();
myBoards = list;
updateMyBoardsKeysAndValues(list);
storeBoardListInDatabase("myBoards", myBoards);
public List<Board> getAllBoards() {
return allBoards;
}
private void updateMyBoardsKeysAndValues(ArrayList<Board> list) {
myBoardsKeys.clear();
myBoardsValues.clear();
public List<Board> getSavedBoards() {
List<Board> saved = new ArrayList<Board>(allBoards.size());
for (Board board : list) {
myBoardsKeys.add(board.key);
myBoardsValues.add(board.value);
for (Board b : allBoards) {
if (b.saved)
saved.add(b);
}
Collections.sort(saved, savedOrder);
return saved;
}
public ArrayList<String> getMyBoardsKeys() {
return myBoardsKeys;
public List<String> getSavedKeys() {
return savedKeys;
}
public ArrayList<String> getMyBoardsValues() {
return myBoardsValues;
public List<String> getSavedValues() {
return savedValues;
}
public boolean getBoardExists(String board) {
for (Board e : allBoards) {
for (Board e : getAllBoards()) {
if (e.value.equals(board)) {
return true;
}
@ -124,101 +79,87 @@ public class BoardManager {
return null;
}
/**
* Try to add value to the supplied list.
*
* @param list
* @param value
*/
public void addBoard(ArrayList<Board> list, String value) {
for (Board board : list) {
if (board.value.equals(value)) {
Toast.makeText(context, R.string.board_add_duplicate, Toast.LENGTH_LONG).show();
return;
}
public void updateSavedBoards() {
long start = Time.get();
ChanApplication.getDatabaseManager().updateBoards(allBoards);
reloadSavedKeysValues();
Logger.d(TAG, "updateSavedBoards took " + Time.get(start));
}
private void reloadSavedKeysValues() {
List<Board> saved = getSavedBoards();
savedKeys.clear();
for (Board board : saved) {
savedKeys.add(board.key);
}
for (Board board : allBoards) {
if (board.value.equals(value)) {
list.add(board);
String text = context.getString(R.string.board_add_success) + " " + board.key;
Toast.makeText(context, text, Toast.LENGTH_LONG).show();
return;
}
savedValues.clear();
for (Board board : saved) {
savedValues.add(board.value);
}
Toast.makeText(context, R.string.board_add_fail, Toast.LENGTH_LONG).show();
}
private ArrayList<Board> loadMyBoards() {
ArrayList<Board> list = getBoardListFromDatabase("myBoards");
if (list == null || list.size() == 0) {
list = getDefaultBoards();
storeBoardListInDatabase("myBoards", list);
private void storeBoards() {
long start = Time.get();
Logger.d(TAG, "Storing boards in database");
for (Board test : allBoards) {
if (test.saved) {
Logger.w(TAG, "Board with value " + test.value + " saved");
}
}
return list;
ChanApplication.getDatabaseManager().setBoards(allBoards);
Logger.d(TAG, "storeBoards took " + Time.get(start));
}
private void storeBoardListInDatabase(String key, ArrayList<Board> list) {
String total = "";
for (Board board : list) {
total += board.key + "|" + board.value + "\n";
private void loadBoards() {
long start = Time.get();
allBoards = ChanApplication.getDatabaseManager().getBoards();
if (allBoards.size() == 0) {
Logger.d(TAG, "Loading default boards");
allBoards = getDefaultBoards();
storeBoards();
}
ChanApplication.getPreferences().edit().putString(key, total).commit();
reloadSavedKeysValues();
Logger.d(TAG, "loadBoards took " + Time.get(start));
}
private ArrayList<Board> getBoardListFromDatabase(String key) {
String total = ChanApplication.getPreferences().getString(key, null);
if (total == null)
return null;
ArrayList<Board> list = new ArrayList<Board>();
Scanner scanner = new Scanner(total);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] splitted = line.split("\\|");
if (splitted.length < 2)
continue;
Board board = new Board();
board.key = splitted[0];
board.value = splitted[1];
if (!board.finish()) {
Logger.wtf(TAG, "board.finish in loadfrompreferences threw up");
private void setBoardsFromServer(List<Board> list) {
boolean changed = false;
for (Board serverBoard : list) {
boolean has = false;
for (Board b : allBoards) {
if (b.valueEquals(serverBoard)) {
has = true;
break;
}
}
if (!has) {
Logger.d(TAG, "Adding unknown board: " + serverBoard.value);
allBoards.add(serverBoard);
changed = true;
}
list.add(board);
}
scanner.close();
return list;
if (changed) {
storeBoards();
}
}
private void loadFromServer() {
ArrayList<Board> temp = getBoardListFromDatabase("allBoards");
if (temp != null) {
allBoards = temp;
}
ChanApplication.getVolleyRequestQueue().add(
new BoardsRequest(ChanUrls.getBoardsUrl(), new Response.Listener<ArrayList<Board>>() {
new BoardsRequest(ChanUrls.getBoardsUrl(), new Response.Listener<List<Board>>() {
@Override
public void onResponse(ArrayList<Board> data) {
storeBoardListInDatabase("allBoards", data);
allBoards = data;
public void onResponse(List<Board> data) {
Logger.i(TAG, "Got boards from server");
setBoardsFromServer(data);
}
}, new Response.ErrorListener() {
@Override
@ -227,4 +168,14 @@ public class BoardManager {
}
}));
}
private List<Board> getDefaultBoards() {
List<Board> list = new ArrayList<Board>();
list.add(new Board("Technology", "g", true, true));
list.add(new Board("Video Games", "v", true, true));
list.add(new Board("Anime & Manga", "a", true, true));
list.add(new Board("Comics & Cartoons", "co", true, true));
list.add(new Board("International", "int", true, true));
return list;
}
}

@ -1,21 +1,43 @@
package org.floens.chan.core.model;
/**
* Board key and value. key is full name e.g. Literature. value is board key
* e.g. lit.
*/
import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
@DatabaseTable
public class Board {
public Board() {
}
public Board(String key, String value, boolean saved, boolean workSafe) {
this.key = key;
this.value = value;
this.saved = saved;
this.workSafe = workSafe;
}
@DatabaseField(generatedId = true)
public int id;
/**
* Name of the board, e.g. Literature
*/
@DatabaseField
public String key;
/**
* Name of the url, e.g. lit
*/
@DatabaseField
public String value;
@DatabaseField
public boolean workSafe = false;
@DatabaseField
public boolean saved = false;
@DatabaseField
public int order;
public boolean finish() {
if (key == null || value == null)
return false;
@ -27,4 +49,8 @@ public class Board {
public String toString() {
return key;
}
public boolean valueEquals(Board other) {
return value.equals(other.value);
}
}

@ -2,6 +2,7 @@ package org.floens.chan.core.net;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.floens.chan.core.model.Board;
@ -10,18 +11,18 @@ import android.util.JsonReader;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
public class BoardsRequest extends JsonReaderRequest<ArrayList<Board>> {
public BoardsRequest(String url, Listener<ArrayList<Board>> listener, ErrorListener errorListener) {
public class BoardsRequest extends JsonReaderRequest<List<Board>> {
public BoardsRequest(String url, Listener<List<Board>> listener, ErrorListener errorListener) {
super(url, listener, errorListener);
}
@Override
public ArrayList<Board> readJson(JsonReader reader) {
public List<Board> readJson(JsonReader reader) {
return parseJson(reader);
}
private ArrayList<Board> parseJson(JsonReader reader) {
ArrayList<Board> list = new ArrayList<Board>();
private List<Board> parseJson(JsonReader reader) {
List<Board> list = new ArrayList<Board>();
try {
reader.beginObject();

@ -2,6 +2,7 @@ package org.floens.chan.database;
import java.sql.SQLException;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Loadable;
import org.floens.chan.core.model.Pin;
import org.floens.chan.core.model.SavedReply;
@ -19,12 +20,13 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
private static final String TAG = "DatabaseHelper";
private static final String DATABASE_NAME = "ChanDB";
private static final int DATABASE_VERSION = 9;
private static final int DATABASE_VERSION = 11;
public Dao<Pin, Integer> pinDao;
public Dao<Loadable, Integer> loadableDao;
public Dao<SavedReply, Integer> savedDao;
public Dao<Board, Integer> boardsDao;
private final Context context;
public DatabaseHelper(Context context) {
@ -36,6 +38,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
pinDao = getDao(Pin.class);
loadableDao = getDao(Loadable.class);
savedDao = getDao(SavedReply.class);
boardsDao = getDao(Board.class);
} catch (SQLException e) {
e.printStackTrace();
}
@ -47,6 +50,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.createTable(connectionSource, Pin.class);
TableUtils.createTable(connectionSource, Loadable.class);
TableUtils.createTable(connectionSource, SavedReply.class);
TableUtils.createTable(connectionSource, Board.class);
} catch (SQLException e) {
Logger.e(TAG, "Error creating db", e);
throw new RuntimeException(e);
@ -76,6 +80,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper {
TableUtils.dropTable(connectionSource, Pin.class, true);
TableUtils.dropTable(connectionSource, Loadable.class, true);
TableUtils.dropTable(connectionSource, SavedReply.class, true);
TableUtils.dropTable(connectionSource, Board.class, true);
onCreate(database, connectionSource);
} catch (SQLException e) {

@ -2,10 +2,13 @@ package org.floens.chan.database;
import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.Callable;
import org.floens.chan.core.model.Board;
import org.floens.chan.core.model.Pin;
import org.floens.chan.core.model.SavedReply;
import org.floens.chan.utils.Logger;
import org.floens.chan.utils.Time;
import android.content.Context;
@ -114,6 +117,54 @@ public class DatabaseManager {
return list;
}
public void setBoards(final List<Board> boards) {
try {
helper.boardsDao.callBatchTasks(new Callable<Void>() {
@Override
public Void call() throws SQLException {
for (Board b : boards) {
helper.boardsDao.createOrUpdate(b);
}
return null;
}
});
} catch (Exception e) {
Logger.e(TAG, "Error setting boards in db", e);
}
}
public void updateBoards(final List<Board> boards) {
try {
helper.boardsDao.callBatchTasks(new Callable<Void>() {
@Override
public Void call() throws SQLException {
long start = Time.get();
for (Board b : boards) {
helper.boardsDao.update(b);
}
Logger.d(TAG, "Update board took " + Time.get(start));
return null;
}
});
} catch (Exception e) {
Logger.e(TAG, "Error updating boards in db", e);
}
}
public List<Board> getBoards() {
List<Board> boards = null;
try {
boards = helper.boardsDao.queryForAll();
} catch (SQLException e) {
Logger.e(TAG, "Error getting boards from db", e);
}
return boards;
}
public String getSummary() {
String o = "";

@ -11,12 +11,11 @@ import org.floens.chan.ui.BadgeDrawable;
import org.floens.chan.ui.SwipeDismissListViewTouchListener;
import org.floens.chan.ui.SwipeDismissListViewTouchListener.DismissCallbacks;
import org.floens.chan.ui.adapter.PinnedAdapter;
import org.floens.chan.utils.Utils;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
@ -33,7 +32,6 @@ import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
@ -221,15 +219,7 @@ public abstract class BaseActivity extends Activity implements PanelSlideListene
}
}).setTitle(R.string.drawer_pinned_change_title).setView(text).create();
text.requestFocus();
dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(text, 0);
}
});
Utils.requestKeyboardFocus(dialog, text);
dialog.show();
}

@ -53,7 +53,7 @@ public class BoardActivity extends BaseActivity implements ActionBar.OnNavigatio
final ActionBar actionBar = getActionBar();
actionBar.setListNavigationCallbacks(
new ArrayAdapter<String>(actionBar.getThemedContext(), R.layout.board_select_spinner,
android.R.id.text1, ChanApplication.getBoardManager().getMyBoardsKeys()), this);
android.R.id.text1, ChanApplication.getBoardManager().getSavedKeys()), this);
updatePaneState();
updateActionBarState();
@ -75,8 +75,10 @@ public class BoardActivity extends BaseActivity implements ActionBar.OnNavigatio
}
if (boardLoadable.mode == Loadable.Mode.INVALID) {
String board = ChanApplication.getBoardManager().getMyBoardsValues().get(0);
loadBoard(board);
List<String> savedValues = ChanApplication.getBoardManager().getSavedValues();
if (savedValues.size() > 0) {
loadBoard(savedValues.get(0));
}
}
}
}
@ -396,8 +398,11 @@ public class BoardActivity extends BaseActivity implements ActionBar.OnNavigatio
if (!actionBarSetToListNavigation) {
actionBarSetToListNavigation = true;
} else {
boardLoadable = new Loadable(ChanApplication.getBoardManager().getMyBoardsValues().get(position));
startLoadingBoard(boardLoadable);
List<String> savedValues = ChanApplication.getBoardManager().getSavedValues();
if (position >= 0 && position < savedValues.size()) {
boardLoadable = new Loadable(savedValues.get(position));
startLoadingBoard(boardLoadable);
}
}
return true;
@ -496,7 +501,7 @@ public class BoardActivity extends BaseActivity implements ActionBar.OnNavigatio
}
private int getBoardIndexNavigator(String boardValue) {
List<String> list = ChanApplication.getBoardManager().getMyBoardsValues();
List<String> list = ChanApplication.getBoardManager().getSavedValues();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).equals(boardValue)) {
return i;

@ -1,31 +1,44 @@
package org.floens.chan.ui.activity;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.floens.chan.ChanApplication;
import org.floens.chan.R;
import org.floens.chan.core.manager.BoardManager;
import org.floens.chan.core.model.Board;
import org.floens.chan.ui.adapter.BoardEditAdapter;
import org.floens.chan.ui.view.DynamicListView;
import org.floens.chan.utils.Logger;
import org.floens.chan.utils.Utils;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.DialogInterface.OnShowListener;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import android.widget.Toast;
public class BoardEditor extends Activity {
private ArrayList<Board> list = new ArrayList<Board>();
private final BoardManager boardManager = ChanApplication.getBoardManager();
private List<Board> list;
private DynamicListView<Board> listView;
private BoardEditAdapter adapter;
private AlertDialog dialog;
@SuppressWarnings("unchecked")
@Override
@ -33,43 +46,84 @@ public class BoardEditor extends Activity {
super.onCreate(savedInstanceState);
setContentView(R.layout.board_edit);
list = boardManager.getSavedBoards();
// Copy not a reference
list = (ArrayList<Board>) ChanApplication.getBoardManager().getMyBoards().clone();
adapter = new BoardEditAdapter(this, R.layout.board_view, list, this);
listView = (DynamicListView<Board>) findViewById(R.id.board_edit_list);
listView.setArrayList(list);
listView.setAdapter(adapter);
reload();
}
@SuppressWarnings("unchecked")
@Override
protected void onPause() {
super.onPause();
// For runtime changes
if (list.size() > 0) {
ChanApplication.getBoardManager().setMyBoards((ArrayList<Board>) list.clone());
// Order
for (int i = 0; i < list.size(); i++) {
list.get(i).order = i;
}
boardManager.updateSavedBoards();
}
}
public void onDeleteClicked(Board board) {
removeBoard(board.value);
}
@Override
protected void onDestroy() {
super.onDestroy();
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.board_edit, menu);
return true;
}
if (dialog != null) {
dialog.dismiss();
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_board:
showAddBoardDialog();
return true;
}
return super.onOptionsItemSelected(item);
}
private void addBoard(String value) {
ChanApplication.getBoardManager().addBoard(list, value);
private void addBoard(final String value) {
for (Board board : list) {
if (board.value.equals(value)) {
Toast.makeText(this, R.string.board_add_duplicate, Toast.LENGTH_LONG).show();
adapter = new BoardEditAdapter(this, R.layout.board_view, list, this);
listView.setArrayList(list);
listView.setAdapter(adapter);
return;
}
}
List<Board> all = ChanApplication.getBoardManager().getAllBoards();
for (Board board : all) {
if (board.value.equals(value)) {
board.saved = true;
list.add(board);
Toast.makeText(this, getString(R.string.board_add_success) + " " + board.key, Toast.LENGTH_LONG).show();
reload();
return;
}
}
String message = getString(R.string.board_add_unknown).replace("CODE", value);
new AlertDialog.Builder(this).setTitle(R.string.board_add_unknown_title).setMessage(message)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (list != null)
list.add(new Board(value, value, true, true));
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}).create().show();
}
private void removeBoard(String value) {
@ -77,32 +131,41 @@ public class BoardEditor extends Activity {
return;
for (int i = 0; i < list.size(); i++) {
Board e = list.get(i);
if (e.value == value) {
Board b = list.get(i);
if (b.value == value) {
list.remove(i);
adapter = new BoardEditAdapter(this, R.layout.board_view, list, this);
listView.setArrayList(list);
listView.setAdapter(adapter);
b.saved = false;
break;
}
}
reload();
}
public void onDeleteClicked(Board board) {
removeBoard(board.value);
private void reload() {
adapter = new BoardEditAdapter(this, R.layout.board_view, list, this);
listView.setArrayList(list);
listView.setAdapter(adapter);
}
private void showAddBoardDialog() {
final EditText text = new EditText(this);
final AutoCompleteTextView text = new AutoCompleteTextView(this);
text.setSingleLine();
dialog = new AlertDialog.Builder(this).setPositiveButton(R.string.add, new DialogInterface.OnClickListener() {
FillAdapter fillAdapter = new FillAdapter(this, 0);
fillAdapter.setEditingList(list);
fillAdapter.setAutoCompleteView(text);
text.setAdapter(fillAdapter);
text.setThreshold(1);
text.setDropDownHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
AlertDialog dialog = new AlertDialog.Builder(this).setPositiveButton(R.string.add, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
String value = text.getText().toString();
if (!TextUtils.isEmpty(value)) {
addBoard(value);
addBoard(value.toLowerCase(Locale.ENGLISH));
}
}
}).setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
@ -111,41 +174,140 @@ public class BoardEditor extends Activity {
}
}).setTitle(R.string.board_add).setView(text).create();
text.requestFocus();
dialog.setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface d) {
dialog = null;
}
});
dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(text, 0);
}
});
Utils.requestKeyboardFocus(dialog, text);
dialog.show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.board_edit, menu);
return true;
}
private static class FillAdapter extends ArrayAdapter<String> implements Filterable {
private List<Board> currentlyEditing;
private View autoCompleteView;
private final Filter filter;
private final List<Board> filtered = new ArrayList<Board>();
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_board:
showAddBoardDialog();
public FillAdapter(Context context, int resource) {
super(context, resource);
return true;
filter = new Filter() {
@Override
protected synchronized FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraint) || (constraint.toString().contains(" "))) {
results.values = null;
results.count = 0;
} else {
List<Board> keys = getFiltered(constraint.toString());
results.values = keys;
results.count = keys.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
filtered.clear();
if (results.values != null) {
filtered.addAll((List<Board>) results.values);
} else {
filtered.addAll(getBoards());
}
notifyDataSetChanged();
}
};
}
return super.onOptionsItemSelected(item);
public void setEditingList(List<Board> list) {
currentlyEditing = list;
}
public void setAutoCompleteView(View autoCompleteView) {
this.autoCompleteView = autoCompleteView;
}
@Override
public int getCount() {
return filtered.size();
}
@Override
public String getItem(int position) {
return filtered.get(position).value;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, null);
Board b = filtered.get(position);
view.setText(b.value + " - " + b.key);
view.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(autoCompleteView.getWindowToken(), 0);
}
return false;
}
});
return view;
}
@Override
public Filter getFilter() {
return filter;
}
private List<Board> getFiltered(String filter) {
String lowered = filter.toLowerCase(Locale.ENGLISH);
List<Board> list = new ArrayList<Board>();
for (Board b : getBoards()) {
if (!haveBoard(b.value)
&& (b.key.toLowerCase(Locale.ENGLISH).contains(lowered) || b.value.toLowerCase(Locale.ENGLISH)
.contains(lowered))) {
list.add(b);
}
}
return list;
}
private boolean haveBoard(String value) {
for (Board b : currentlyEditing) {
if (b.value.equals(value))
return true;
}
return false;
}
private List<Board> getBoards() {
// Lets be cheaty here: if the user has nsfw boards in the list,
// show them in the autofiller.
boolean showUnsafe = false;
for (Board has : currentlyEditing) {
if (!has.workSafe) {
Logger.test("Unsafe: " + has.key + ", " + has.workSafe);
showUnsafe = true;
break;
}
}
Logger.test("Showing unsafe: " + showUnsafe + ", " + currentlyEditing.size());
List<Board> s = new ArrayList<Board>();
for (Board b : ChanApplication.getBoardManager().getAllBoards()) {
if (showUnsafe || b.workSafe)
s.add(b);
}
return s;
}
}
}

@ -9,6 +9,7 @@ import org.floens.chan.core.model.Post;
import org.floens.chan.ui.ScrollerRunnable;
import org.floens.chan.ui.view.PostView;
import org.floens.chan.ui.view.ThreadWatchCounterView;
import org.floens.chan.utils.Time;
import org.floens.chan.utils.Utils;
import android.content.Context;
@ -62,8 +63,8 @@ public class PostAdapter extends BaseAdapter {
}
if (position >= postList.size()) {
if (System.currentTimeMillis() - lastViewedTime > 10000L) {
lastViewedTime = System.currentTimeMillis();
if (Time.get(lastViewedTime) > 10000L) {
lastViewedTime = Time.get();
threadManager.bottomPostViewed();
}

@ -16,7 +16,7 @@
package org.floens.chan.ui.view;
import java.util.ArrayList;
import java.util.List;
import org.floens.chan.ui.adapter.BoardEditAdapter;
@ -70,7 +70,7 @@ public class DynamicListView<T> extends ListView {
private final int MOVE_DURATION = 150;
private final int LINE_THICKNESS = 10;
public ArrayList<T> mCheeseList;
public List<T> mCheeseList;
private int mLastEventY = -1;
@ -372,7 +372,7 @@ public class DynamicListView<T> extends ListView {
}
}
private void swapElements(ArrayList<T> arrayList, int indexOne, int indexTwo) {
private void swapElements(List<T> arrayList, int indexOne, int indexTwo) {
T temp = arrayList.get(indexOne);
arrayList.set(indexOne, arrayList.get(indexTwo));
arrayList.set(indexTwo, temp);
@ -501,7 +501,7 @@ public class DynamicListView<T> extends ListView {
return false;
}
public void setArrayList(ArrayList<T> cheeseList) {
public void setArrayList(List<T> cheeseList) {
mCheeseList = cheeseList;
}

@ -7,6 +7,7 @@ import org.floens.chan.core.manager.ThreadManager;
import org.floens.chan.core.model.Post;
import org.floens.chan.core.model.PostLinkable;
import org.floens.chan.utils.IconCache;
import org.floens.chan.utils.Time;
import org.floens.chan.utils.Utils;
import android.app.Activity;
@ -126,7 +127,7 @@ public class PostView extends LinearLayout implements View.OnClickListener, View
total = TextUtils.concat(total, post.capcodeSpan, " ");
}
CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(post.time * 1000L, System.currentTimeMillis(),
CharSequence relativeTime = DateUtils.getRelativeTimeSpanString(post.time * 1000L, Time.get(),
DateUtils.SECOND_IN_MILLIS, 0);
SpannableString date = new SpannableString("No." + post.no + " " + relativeTime);

@ -0,0 +1,11 @@
package org.floens.chan.utils;
public class Time {
public static long get() {
return System.currentTimeMillis();
}
public static long get(long other) {
return System.currentTimeMillis() - other;
}
}

@ -2,7 +2,10 @@ package org.floens.chan.utils;
import org.floens.chan.ChanApplication;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnShowListener;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
@ -10,6 +13,7 @@ import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
public class Utils {
private static DisplayMetrics displayMetrics;
@ -63,4 +67,15 @@ public class Utils {
public static void runOnUiThread(Runnable runnable) {
new Handler(Looper.getMainLooper()).post(runnable);
}
public static void requestKeyboardFocus(Dialog dialog, final View view) {
view.requestFocus();
dialog.setOnShowListener(new OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(view, 0);
}
});
}
}

Loading…
Cancel
Save