Add history

filtering
Floens 10 years ago
parent 19e7066f82
commit 3b250b82b6
  1. 18
      Clover/app/src/main/java/org/floens/chan/core/database/DatabaseHelper.java
  2. 125
      Clover/app/src/main/java/org/floens/chan/core/database/DatabaseManager.java
  3. 36
      Clover/app/src/main/java/org/floens/chan/core/model/History.java
  4. 2
      Clover/app/src/main/java/org/floens/chan/core/model/Loadable.java
  5. 17
      Clover/app/src/main/java/org/floens/chan/core/presenter/ThreadPresenter.java
  6. 4
      Clover/app/src/main/java/org/floens/chan/core/settings/ChanSettings.java
  7. 244
      Clover/app/src/main/java/org/floens/chan/ui/controller/HistoryController.java
  8. 21
      Clover/app/src/main/java/org/floens/chan/ui/controller/RootNavigationController.java
  9. 2
      Clover/app/src/main/java/org/floens/chan/ui/controller/ThreadController.java
  10. 8
      Clover/app/src/main/java/org/floens/chan/ui/toolbar/Toolbar.java
  11. BIN
      Clover/app/src/main/res/drawable-hdpi/ic_search_white_24dp.png
  12. BIN
      Clover/app/src/main/res/drawable-mdpi/ic_search_white_24dp.png
  13. BIN
      Clover/app/src/main/res/drawable-xhdpi/ic_search_white_24dp.png
  14. BIN
      Clover/app/src/main/res/drawable-xxhdpi/ic_search_white_24dp.png
  15. BIN
      Clover/app/src/main/res/drawable-xxxhdpi/ic_search_white_24dp.png
  16. 92
      Clover/app/src/main/res/layout/cell_history.xml
  17. 2
      Clover/app/src/main/res/layout/cell_pin.xml
  18. 26
      Clover/app/src/main/res/layout/controller_history.xml
  19. 4
      Clover/app/src/main/res/values/strings.xml
  20. 8
      docs/database.txt

@ -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<Pin, Integer> pinDao;
public Dao<Loadable, Integer> loadableDao;
public Dao<SavedReply, Integer> savedDao;
public Dao<Board, Integer> boardsDao;
public Dao<ThreadHide, Integer> threadHideDao;
public Dao<History, Integer> 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() {

@ -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<ThreadHide> threadHides = new ArrayList<>();
private final HashSet<Integer> threadHidesIds = new HashSet<>();
private final Object historyLock = new Object();
private final HashMap<Loadable, History> 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<Void>() {
@Override
public Void call() throws Exception {
List<History> 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<History> getHistory() {
List<History> list = null;
try {
QueryBuilder<History, Integer> 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<History> 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<Void>() {
@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.
*

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}

@ -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

@ -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);

@ -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

@ -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 <http://www.gnu.org/licenses/>.
*/
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<FloatingMenuItem> 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<HistoryCell> {
private List<History> sourceList = new ArrayList<>();
private List<History> 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);
}
}
}
}
}

@ -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);

@ -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;

@ -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) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 915 B

@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?><!--
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 <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/item_background"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<org.floens.chan.ui.view.ThumbnailView
android:id="@+id/thumbnail"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:paddingBottom="4dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingTop="4dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp"
android:singleLine="true"
android:textColor="?text_color_primary"
android:textSize="14sp" />
<TextView
android:id="@+id/subtext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="?text_color_secondary"
android:textSize="12sp" />
</LinearLayout>
<ImageView
android:id="@+id/delete"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center_vertical"
android:paddingBottom="4dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingTop="4dp"
tools:ignore="ContentDescription" />
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:background="?attr/divider_color" />
</LinearLayout>

@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackground"
android:background="@drawable/item_background"
android:orientation="horizontal">
<org.floens.chan.ui.view.ThumbnailView

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?><!--
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 <http://www.gnu.org/licenses/>.
-->
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?backcolor"
android:clipToPadding="false"
android:padding="16dp"
android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical" />

@ -114,6 +114,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="board_add_unknown">The board with code %1$s is not known.</string>
<string name="board_edit_sort_a_z">Sort A-Z</string>
<string name="history_clear">Clear history</string>
<string name="history_clear_confirm">Clear history?</string>
<string name="history_clear_confirm_button">Clear</string>
<string name="drawer_board">Board</string>
<string name="drawer_catalog">Catalog</string>
<string name="drawer_pinned">Watching threads</string>

@ -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 )

Loading…
Cancel
Save