diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java index 7a916fa0..6e57372d 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java @@ -26,6 +26,7 @@ import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; import org.floens.chan.core.model.Board; +import org.floens.chan.core.model.History; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.SavedReply; @@ -41,13 +42,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { private static final String TAG = "DatabaseHelper"; private static final String DATABASE_NAME = "ChanDB"; - private static final int DATABASE_VERSION = 17; + private static final int DATABASE_VERSION = 18; public Dao pinDao; public Dao loadableDao; public Dao savedDao; public Dao boardsDao; public Dao threadHideDao; + public Dao historyDao; private final Context context; @@ -62,6 +64,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { savedDao = getDao(SavedReply.class); boardsDao = getDao(Board.class); threadHideDao = getDao(ThreadHide.class); + historyDao = getDao(History.class); } catch (SQLException e) { Logger.e(TAG, "Error creating Daos", e); } @@ -75,6 +78,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { TableUtils.createTable(connectionSource, SavedReply.class); TableUtils.createTable(connectionSource, Board.class); TableUtils.createTable(connectionSource, ThreadHide.class); + TableUtils.createTable(connectionSource, History.class); } catch (SQLException e) { Logger.e(TAG, "Error creating db", e); throw new RuntimeException(e); @@ -150,9 +154,7 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { if (oldVersion < 16) { try { - // WARNING: change this to a sql query when the columns need to be altered later on! - // Otherwise it could create a table with the columns already added, and an add column query could error out. - TableUtils.createTable(connectionSource, ThreadHide.class); + threadHideDao.executeRawNoArgs("CREATE TABLE `threadhide` (`board` VARCHAR , `id` INTEGER PRIMARY KEY AUTOINCREMENT , `no` INTEGER );"); } catch (SQLException e) { Logger.e(TAG, "Error upgrading to version 16", e); } @@ -165,6 +167,14 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { Logger.e(TAG, "Error upgrading to version 17", e); } } + + if (oldVersion < 18) { + try { + historyDao.executeRawNoArgs("CREATE TABLE `history` (`date` BIGINT , `id` INTEGER PRIMARY KEY AUTOINCREMENT , `loadable_id` INTEGER NOT NULL , `thumbnailUrl` VARCHAR );"); + } catch (SQLException e) { + Logger.e(TAG, "Error upgrading to version 18", e); + } + } } public void reset() { diff --git a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java index 7a8b9f7b..60149818 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java +++ b/Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java @@ -20,9 +20,13 @@ package org.floens.chan.core.database; import android.content.Context; import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.misc.TransactionManager; +import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.table.TableUtils; import org.floens.chan.core.model.Board; +import org.floens.chan.core.model.History; +import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; import org.floens.chan.core.model.SavedReply; @@ -31,9 +35,12 @@ import org.floens.chan.utils.Logger; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import static com.j256.ormlite.misc.TransactionManager.callInTransaction; @@ -44,6 +51,10 @@ public class DatabaseManager { private static final long SAVED_REPLY_TRIM_COUNT = 50; private static final long THREAD_HIDE_TRIM_TRIGGER = 250; private static final long THREAD_HIDE_TRIM_COUNT = 50; + private static final long HISTORY_TRIM_TRIGGER = 500; + private static final long HISTORY_TRIM_COUNT = 50; + + private final ExecutorService backgroundExecutor = Executors.newSingleThreadExecutor(); private final DatabaseHelper helper; @@ -54,6 +65,9 @@ public class DatabaseManager { private final List threadHides = new ArrayList<>(); private final HashSet threadHidesIds = new HashSet<>(); + private final Object historyLock = new Object(); + private final HashMap historyByLoadable = new HashMap<>(); + public DatabaseManager(Context context) { helper = new DatabaseHelper(context); initialize(); @@ -199,6 +213,74 @@ public class DatabaseManager { return list; } + /** + * Adds or updates a {@link History} to the history table. + * Only updates the date if the history is already in the table. + * + * @param history History to save + */ + public void addHistory(final History history) { + backgroundExecutor.submit(new Runnable() { + @Override + public void run() { + addHistoryInternal(history); + } + }); + } + + /** + * Deletes a {@link History} from the history table. + * + * @param history History to delete + */ + public void removeHistory(History history) { + try { + helper.historyDao.delete(history); + helper.loadableDao.delete(history.loadable); + historyByLoadable.remove(history.loadable); + } catch (SQLException e) { + Logger.e(TAG, "Error removing history from db", e); + } + } + + /** + * Clears all history and the referenced loadables from the database. + */ + public void clearHistory() { + try { + TransactionManager.callInTransaction(helper.getConnectionSource(), new Callable() { + @Override + public Void call() throws Exception { + List historyList = getHistory(); + for (History history : historyList) { + removeHistory(history); + } + + return null; + } + }); + } catch (SQLException e) { + Logger.e(TAG, "Error clearing history", e); + } + } + + /** + * Get a list of {@link History} entries from the history table. + * + * @return List of History + */ + public List getHistory() { + List list = null; + try { + QueryBuilder historyQuery = helper.historyDao.queryBuilder(); + list = historyQuery.orderBy("date", false).query(); + } catch (SQLException e) { + Logger.e(TAG, "Error getting history from db", e); + } + + return list; + } + /** * Create or updates these boards in the boards table. * @@ -330,6 +412,7 @@ public class DatabaseManager { private void initialize() { loadSavedReplies(); loadThreadHides(); + loadHistory(); } /** @@ -367,6 +450,48 @@ public class DatabaseManager { } } + private void loadHistory() { + synchronized (historyLock) { + try { + trimTable(helper.historyDao, "history", HISTORY_TRIM_TRIGGER, HISTORY_TRIM_COUNT); + + historyByLoadable.clear(); + List historyList = helper.historyDao.queryForAll(); + for (History history : historyList) { + historyByLoadable.put(history.loadable, history); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + } + + private void addHistoryInternal(final History history) { + try { + TransactionManager.callInTransaction(helper.getConnectionSource(), new Callable() { + @Override + public Void call() throws Exception { + synchronized (historyLock) { + History existingHistory = historyByLoadable.get(history.loadable); + if (existingHistory != null) { + existingHistory.date = System.currentTimeMillis(); + helper.historyDao.update(existingHistory); + } else { + history.date = System.currentTimeMillis(); + helper.loadableDao.create(history.loadable); + helper.historyDao.create(history); + historyByLoadable.put(history.loadable, history); + } + } + + return null; + } + }); + } catch (SQLException e) { + Logger.e(TAG, "Error adding history", e); + } + } + /** * Trim a table with the specified trigger and trim count. * diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/History.java b/Clover/app/src/main/java/org/floens/chan/core/model/History.java new file mode 100644 index 00000000..43c14710 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/core/model/History.java @@ -0,0 +1,36 @@ +/* + * 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.model; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +@DatabaseTable +public class History { + @DatabaseField(generatedId = true) + public int id; + + @DatabaseField(canBeNull = false, foreign = true, foreignAutoRefresh = true) + public Loadable loadable; + + @DatabaseField + public String thumbnailUrl; + + @DatabaseField + public long date; +} diff --git a/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java b/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java index 6c2ac3e2..ca2ccdb1 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java +++ b/Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java @@ -93,7 +93,7 @@ public class Loadable { Loadable other = (Loadable) object; - return mode == other.mode && board.equals(other.board) && no == other.no; + return no == other.no && mode == other.mode && board.equals(other.board); } @Override diff --git a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java index 3b4cd8d7..5ccf6aa5 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java +++ b/Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java @@ -25,10 +25,12 @@ import org.floens.chan.Chan; import org.floens.chan.R; import org.floens.chan.chan.ChanLoader; import org.floens.chan.chan.ChanUrls; +import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.core.http.DeleteHttpCall; import org.floens.chan.core.http.ReplyManager; import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.ChanThread; +import org.floens.chan.core.model.History; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; @@ -37,7 +39,6 @@ import org.floens.chan.core.model.PostLinkable; import org.floens.chan.core.model.SavedReply; import org.floens.chan.core.net.LoaderPool; import org.floens.chan.core.settings.ChanSettings; -import org.floens.chan.core.database.DatabaseManager; import org.floens.chan.ui.adapter.PostAdapter; import org.floens.chan.ui.adapter.PostFilter; import org.floens.chan.ui.cell.PostCellInterface; @@ -79,6 +80,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt private boolean searchOpen = false; private String searchQuery; private PostFilter.Order order = PostFilter.Order.BUMP; + private boolean historyAdded = false; public ThreadPresenter(ThreadPresenterCallback threadPresenterCallback) { this.threadPresenterCallback = threadPresenterCallback; @@ -112,6 +114,7 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt LoaderPool.getInstance().release(chanLoader, this); chanLoader = null; loadable = null; + historyAdded = false; threadPresenterCallback.showLoading(); } @@ -224,6 +227,8 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt } loadable.markedNo = -1; } + + addHistory(); } @Override @@ -562,6 +567,16 @@ public class ThreadPresenter implements ChanLoader.ChanLoaderCallback, PostAdapt threadPresenterCallback.showPosts(chanLoader.getThread(), new PostFilter(order, searchQuery)); } + private void addHistory() { + if (!historyAdded && ChanSettings.historyEnabled.get() && loadable.isThreadMode()) { + historyAdded = true; + History history = new History(); + history.loadable = loadable; + history.thumbnailUrl = chanLoader.getThread().op.thumbnailUrl; + databaseManager.addHistory(history); + } + } + public interface ThreadPresenterCallback { void showPosts(ChanThread thread, PostFilter filter); 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 4f6ae8b4..a85ab6d1 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 @@ -94,6 +94,8 @@ public class ChanSettings { public static final StringSetting passPin; public static final StringSetting passId; + public static final BooleanSetting historyEnabled; + static { SharedPreferences p = AndroidUtils.getPreferences(); @@ -155,6 +157,8 @@ public class ChanSettings { passPin = new StringSetting(p, "preference_pass_pin", ""); passId = new StringSetting(p, "preference_pass_id", ""); + historyEnabled = new BooleanSetting(p, "preference_history_enabled", true); + // Old (but possibly still in some users phone) // preference_board_view_mode default "list" // preference_board_editor_filler default false diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java new file mode 100644 index 00000000..030b9565 --- /dev/null +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java @@ -0,0 +1,244 @@ +/* + * 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.ui.controller; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.SwitchCompat; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.TextView; + +import org.floens.chan.Chan; +import org.floens.chan.R; +import org.floens.chan.controller.Controller; +import org.floens.chan.core.database.DatabaseManager; +import org.floens.chan.core.model.Board; +import org.floens.chan.core.model.History; +import org.floens.chan.core.settings.ChanSettings; +import org.floens.chan.ui.toolbar.ToolbarMenu; +import org.floens.chan.ui.toolbar.ToolbarMenuItem; +import org.floens.chan.ui.view.FloatingMenuItem; +import org.floens.chan.ui.view.ThumbnailView; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import static org.floens.chan.ui.theme.ThemeHelper.theme; +import static org.floens.chan.utils.AndroidUtils.dp; + +public class HistoryController extends Controller implements CompoundButton.OnCheckedChangeListener, ToolbarMenuItem.ToolbarMenuItemCallback, RootNavigationController.ToolbarSearchCallback { + private static final int SEARCH_ID = 1; + private static final int CLEAR_ID = 101; + + private DatabaseManager databaseManager; + private RecyclerView recyclerView; + private HistoryAdapter adapter; + + public HistoryController(Context context) { + super(context); + } + + @Override + public void onCreate() { + super.onCreate(); + + databaseManager = Chan.getDatabaseManager(); + + navigationItem.title = string(R.string.history_screen); + List items = new ArrayList<>(); + items.add(new FloatingMenuItem(CLEAR_ID, R.string.history_clear)); + navigationItem.menu = new ToolbarMenu(context); + navigationItem.menu.addItem(new ToolbarMenuItem(context, this, SEARCH_ID, R.drawable.ic_search_white_24dp)); + navigationItem.createOverflow(context, this, items); + + view = inflateRes(R.layout.controller_history); + + SwitchCompat globalSwitch = new SwitchCompat(context); + globalSwitch.setChecked(ChanSettings.historyEnabled.get()); + globalSwitch.setOnCheckedChangeListener(this); + navigationItem.rightView = globalSwitch; + + recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); + recyclerView.setHasFixedSize(true); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); + + adapter = new HistoryAdapter(); + recyclerView.setAdapter(adapter); + adapter.load(); + } + + @Override + public void onMenuItemClicked(ToolbarMenuItem item) { + if ((Integer) item.getId() == SEARCH_ID) { + navigationController.showSearch(); + } + } + + @Override + public void onSubMenuItemClicked(ToolbarMenuItem parent, FloatingMenuItem item) { + if ((Integer) item.getId() == CLEAR_ID) { + new AlertDialog.Builder(context) + .setTitle(R.string.history_clear_confirm) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.history_clear_confirm_button, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + databaseManager.clearHistory(); + adapter.load(); + } + }) + .show(); + } + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + ChanSettings.historyEnabled.set(isChecked); + } + + private void openThread(History history) { + ViewThreadController viewThreadController = new ViewThreadController(context); + viewThreadController.setLoadable(history.loadable); + navigationController.pushController(viewThreadController); + } + + private void deleteHistory(History history) { + databaseManager.removeHistory(history); + adapter.load(); + } + + @Override + public void onSearchVisibilityChanged(boolean visible) { + if (!visible) { + adapter.search(null); + } + } + + @Override + public void onSearchEntered(String entered) { + adapter.search(entered); + } + + private class HistoryAdapter extends RecyclerView.Adapter { + private List sourceList = new ArrayList<>(); + private List displayList = new ArrayList<>(); + private String searchQuery; + + public HistoryAdapter() { + setHasStableIds(true); + } + + @Override + public HistoryCell onCreateViewHolder(ViewGroup parent, int viewType) { + return new HistoryCell(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_history, parent, false)); + } + + @Override + public void onBindViewHolder(HistoryCell holder, int position) { + History history = displayList.get(position); + holder.thumbnail.setUrl(history.thumbnailUrl, dp(48), dp(48)); + holder.text.setText(history.loadable.title); + Board board = Chan.getBoardManager().getBoardByValue(history.loadable.board); + holder.subtext.setText(board == null ? null : ("/" + board.value + "/ - " + board.key)); + } + + @Override + public int getItemCount() { + return displayList.size(); + } + + @Override + public long getItemId(int position) { + return displayList.get(position).id; + } + + public void search(String query) { + this.searchQuery = query; + filter(); + } + + private void load() { + sourceList.clear(); + sourceList.addAll(databaseManager.getHistory()); + + filter(); + } + + private void filter() { + displayList.clear(); + if (!TextUtils.isEmpty(searchQuery)) { + String query = searchQuery.toLowerCase(Locale.ENGLISH); + for (History history : sourceList) { + if (history.loadable.title.toLowerCase(Locale.ENGLISH).contains(query)) { + displayList.add(history); + } + } + } else { + displayList.addAll(sourceList); + } + + notifyDataSetChanged(); + } + } + + private class HistoryCell extends RecyclerView.ViewHolder implements View.OnClickListener { + private ThumbnailView thumbnail; + private TextView text; + private TextView subtext; + private ImageView delete; + + public HistoryCell(View itemView) { + super(itemView); + + thumbnail = (ThumbnailView) itemView.findViewById(R.id.thumbnail); + thumbnail.setCircular(true); + text = (TextView) itemView.findViewById(R.id.text); + subtext = (TextView) itemView.findViewById(R.id.subtext); + delete = (ImageView) itemView.findViewById(R.id.delete); + + theme().clearDrawable.apply(delete); + + delete.setOnClickListener(this); + + itemView.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + int position = getAdapterPosition(); + if (position >= 0 && position < adapter.getItemCount()) { + History history = adapter.displayList.get(position); + if (v == itemView) { + openThread(history); + } else if (v == delete) { + deleteHistory(history); + } + } + + } + } +} diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java index d5dbea5e..8256fa14 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java @@ -178,8 +178,8 @@ public class RootNavigationController extends NavigationController implements Pi @Override public void onPinClicked(Pin pin) { Controller top = getTop(); - if (top instanceof DrawerCallbacks) { - ((DrawerCallbacks) top).onPinClicked(pin); + if (top instanceof DrawerCallback) { + ((DrawerCallback) top).onPinClicked(pin); drawerLayout.closeDrawer(Gravity.LEFT); pinAdapter.updateHighlighted(recyclerView); } @@ -187,8 +187,8 @@ public class RootNavigationController extends NavigationController implements Pi public boolean isHighlighted(Pin pin) { Controller top = getTop(); - if (top instanceof DrawerCallbacks) { - return ((DrawerCallbacks) top).isPinCurrent(pin); + if (top instanceof DrawerCallback) { + return ((DrawerCallback) top).isPinCurrent(pin); } return false; } @@ -256,6 +256,7 @@ public class RootNavigationController extends NavigationController implements Pi @Override public void openHistory() { + pushController(new HistoryController(context)); } public void onEvent(WatchManager.PinAddedMessage message) { @@ -313,24 +314,26 @@ public class RootNavigationController extends NavigationController implements Pi @Override public void onSearchVisibilityChanged(boolean visible) { Controller top = getTop(); - if (top instanceof DrawerCallbacks) { - ((DrawerCallbacks) top).onSearchVisibilityChanged(visible); + if (top instanceof ToolbarSearchCallback) { + ((ToolbarSearchCallback) top).onSearchVisibilityChanged(visible); } } @Override public void onSearchEntered(String entered) { Controller top = getTop(); - if (top instanceof DrawerCallbacks) { - ((DrawerCallbacks) top).onSearchEntered(entered); + if (top instanceof ToolbarSearchCallback) { + ((ToolbarSearchCallback) top).onSearchEntered(entered); } } - public interface DrawerCallbacks { + public interface DrawerCallback { void onPinClicked(Pin pin); boolean isPinCurrent(Pin pin); + } + public interface ToolbarSearchCallback { void onSearchVisibilityChanged(boolean visible); void onSearchEntered(String entered); diff --git a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java index 60ce48eb..02869bea 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java @@ -33,7 +33,7 @@ import java.util.List; import de.greenrobot.event.EventBus; -public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, RootNavigationController.DrawerCallbacks, SwipeRefreshLayout.OnRefreshListener { +public abstract class ThreadController extends Controller implements ThreadLayout.ThreadLayoutCallback, ImageViewerController.PreviewCallback, RootNavigationController.DrawerCallback, SwipeRefreshLayout.OnRefreshListener, RootNavigationController.ToolbarSearchCallback { protected ThreadLayout threadLayout; private SwipeRefreshLayout swipeRefreshLayout; diff --git a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java index 9c9d1fc6..9bf27ab1 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java @@ -394,15 +394,15 @@ public class Toolbar extends LinearLayout implements View.OnClickListener, LoadV titleContainer.removeView(subtitleView); } - if (item.menu != null) { - menu.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); - } - if (item.rightView != null) { item.rightView.setPadding(0, 0, dp(16), 0); menu.addView(item.rightView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); } + if (item.menu != null) { + menu.addView(item.menu, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT)); + } + AndroidUtils.waitForMeasure(titleView, new AndroidUtils.OnMeasuredCallback() { @Override public boolean onMeasured(View view) { diff --git a/Clover/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png b/Clover/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png new file mode 100644 index 00000000..bbfbc96c Binary files /dev/null and b/Clover/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png differ diff --git a/Clover/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png b/Clover/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png new file mode 100644 index 00000000..faefc59c Binary files /dev/null and b/Clover/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png differ diff --git a/Clover/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png b/Clover/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png new file mode 100644 index 00000000..bfc3e393 Binary files /dev/null and b/Clover/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png differ diff --git a/Clover/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png b/Clover/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png new file mode 100644 index 00000000..abbb9895 Binary files /dev/null and b/Clover/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png differ diff --git a/Clover/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png b/Clover/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png new file mode 100644 index 00000000..dd5adfc7 Binary files /dev/null and b/Clover/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png differ diff --git a/Clover/app/src/main/res/layout/cell_history.xml b/Clover/app/src/main/res/layout/cell_history.xml new file mode 100644 index 00000000..08c29766 --- /dev/null +++ b/Clover/app/src/main/res/layout/cell_history.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Clover/app/src/main/res/layout/cell_pin.xml b/Clover/app/src/main/res/layout/cell_pin.xml index 257cb680..304d71cb 100644 --- a/Clover/app/src/main/res/layout/cell_pin.xml +++ b/Clover/app/src/main/res/layout/cell_pin.xml @@ -18,7 +18,7 @@ along with this program. If not, see . + diff --git a/Clover/app/src/main/res/values/strings.xml b/Clover/app/src/main/res/values/strings.xml index a738d8f8..aeba43b1 100644 --- a/Clover/app/src/main/res/values/strings.xml +++ b/Clover/app/src/main/res/values/strings.xml @@ -114,6 +114,10 @@ along with this program. If not, see . The board with code %1$s is not known. Sort A-Z + Clear history + Clear history? + Clear + Board Catalog Watching threads diff --git a/docs/database.txt b/docs/database.txt index cc76422b..cf5d2edc 100644 --- a/docs/database.txt +++ b/docs/database.txt @@ -41,8 +41,14 @@ ALTER TABLE pin ADD COLUMN order INTEGER; Changes is version 15: ALTER TABLE pin ADD COLUMN archived INTEGER; + Changes in version 16: -Table ThreadHide added +CREATE TABLE `threadhide` (`board` VARCHAR , `id` INTEGER PRIMARY KEY AUTOINCREMENT , `no` INTEGER ) + Changes is version 17: ALTER TABLE board ADD COLUMN description TEXT; + + +Changes in version 18: +CREATE TABLE `history` (`date` BIGINT , `id` INTEGER PRIMARY KEY AUTOINCREMENT , `loadable_id` INTEGER NOT NULL , `thumbnailUrl` VARCHAR )