mirror of https://github.com/kurisufriend/Clover
redo the browse controller middle menu to support multiple sites.multisite
parent
8a86b2d7c3
commit
99ce139bf8
@ -0,0 +1,131 @@ |
|||||||
|
/* |
||||||
|
* 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.presenter; |
||||||
|
|
||||||
|
import android.util.Pair; |
||||||
|
|
||||||
|
import org.floens.chan.core.database.DatabaseManager; |
||||||
|
import org.floens.chan.core.manager.BoardManager; |
||||||
|
import org.floens.chan.core.model.orm.Board; |
||||||
|
import org.floens.chan.core.model.orm.Loadable; |
||||||
|
import org.floens.chan.core.site.Site; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Observable; |
||||||
|
import java.util.Observer; |
||||||
|
|
||||||
|
import javax.inject.Inject; |
||||||
|
|
||||||
|
public class BrowsePresenter implements Observer { |
||||||
|
private final DatabaseManager databaseManager; |
||||||
|
private final BoardManager boardManager; |
||||||
|
private Callback callback; |
||||||
|
|
||||||
|
private boolean hadBoards = false; |
||||||
|
private Board currentBoard; |
||||||
|
|
||||||
|
private BoardManager.SavedBoards savedBoardsObservable; |
||||||
|
|
||||||
|
@Inject |
||||||
|
public BrowsePresenter(DatabaseManager databaseManager, BoardManager boardManager) { |
||||||
|
this.databaseManager = databaseManager; |
||||||
|
this.boardManager = boardManager; |
||||||
|
|
||||||
|
savedBoardsObservable = boardManager.getSavedBoardsObservable(); |
||||||
|
|
||||||
|
hadBoards = hasBoards(); |
||||||
|
} |
||||||
|
|
||||||
|
public void create(Callback callback) { |
||||||
|
this.callback = callback; |
||||||
|
|
||||||
|
savedBoardsObservable.addObserver(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void destroy() { |
||||||
|
savedBoardsObservable.deleteObserver(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Board currentBoard() { |
||||||
|
return currentBoard; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBoard(Board board) { |
||||||
|
loadBoard(board); |
||||||
|
} |
||||||
|
|
||||||
|
public void onBoardsFloatingMenuBoardClicked(Board board) { |
||||||
|
loadBoard(board); |
||||||
|
} |
||||||
|
|
||||||
|
public void loadWithDefaultBoard() { |
||||||
|
loadBoard(firstBoard()); |
||||||
|
} |
||||||
|
|
||||||
|
public void onBoardsFloatingMenuSiteClicked(Site site) { |
||||||
|
callback.loadSiteSetup(site); |
||||||
|
} |
||||||
|
|
||||||
|
public BoardManager.SavedBoards getSavedBoardsObservable() { |
||||||
|
return boardManager.getSavedBoardsObservable(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(Observable o, Object arg) { |
||||||
|
if (o == savedBoardsObservable) { |
||||||
|
if (!hadBoards && hasBoards()) { |
||||||
|
hadBoards = true; |
||||||
|
loadWithDefaultBoard(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private boolean hasBoards() { |
||||||
|
for (Pair<Site, List<Board>> siteListPair : savedBoardsObservable.get()) { |
||||||
|
if (!siteListPair.second.isEmpty()) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
private Board firstBoard() { |
||||||
|
for (Pair<Site, List<Board>> siteListPair : savedBoardsObservable.get()) { |
||||||
|
if (!siteListPair.second.isEmpty()) { |
||||||
|
return siteListPair.second.get(0); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private Loadable getLoadableForBoard(Board board) { |
||||||
|
return databaseManager.getDatabaseLoadableManager().get(Loadable.forCatalog(board)); |
||||||
|
} |
||||||
|
|
||||||
|
private void loadBoard(Board board) { |
||||||
|
currentBoard = board; |
||||||
|
callback.loadBoard(getLoadableForBoard(board)); |
||||||
|
} |
||||||
|
|
||||||
|
public interface Callback { |
||||||
|
void loadBoard(Loadable loadable); |
||||||
|
|
||||||
|
void loadSiteSetup(Site site); |
||||||
|
} |
||||||
|
} |
@ -1,478 +0,0 @@ |
|||||||
/* |
|
||||||
* 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.annotation.SuppressLint; |
|
||||||
import android.content.Context; |
|
||||||
import android.content.DialogInterface; |
|
||||||
import android.support.design.widget.FloatingActionButton; |
|
||||||
import android.support.design.widget.Snackbar; |
|
||||||
import android.support.v7.app.AlertDialog; |
|
||||||
import android.support.v7.widget.LinearLayoutManager; |
|
||||||
import android.support.v7.widget.RecyclerView; |
|
||||||
import android.support.v7.widget.helper.ItemTouchHelper; |
|
||||||
import android.text.TextUtils; |
|
||||||
import android.view.LayoutInflater; |
|
||||||
import android.view.MotionEvent; |
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewGroup; |
|
||||||
import android.view.inputmethod.EditorInfo; |
|
||||||
import android.widget.ArrayAdapter; |
|
||||||
import android.widget.AutoCompleteTextView; |
|
||||||
import android.widget.Filter; |
|
||||||
import android.widget.Filterable; |
|
||||||
import android.widget.ImageView; |
|
||||||
import android.widget.LinearLayout; |
|
||||||
import android.widget.TextView; |
|
||||||
|
|
||||||
import org.floens.chan.R; |
|
||||||
import org.floens.chan.controller.Controller; |
|
||||||
import org.floens.chan.core.manager.BoardManager; |
|
||||||
import org.floens.chan.core.model.orm.Board; |
|
||||||
import org.floens.chan.ui.helper.BoardHelper; |
|
||||||
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.utils.AndroidUtils; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.Collections; |
|
||||||
import java.util.Comparator; |
|
||||||
import java.util.List; |
|
||||||
import java.util.Locale; |
|
||||||
|
|
||||||
import javax.inject.Inject; |
|
||||||
|
|
||||||
import static org.floens.chan.Chan.getGraph; |
|
||||||
import static org.floens.chan.ui.theme.ThemeHelper.theme; |
|
||||||
import static org.floens.chan.utils.AndroidUtils.dp; |
|
||||||
import static org.floens.chan.utils.AndroidUtils.fixSnackbarText; |
|
||||||
import static org.floens.chan.utils.AndroidUtils.getString; |
|
||||||
|
|
||||||
public class BoardEditController extends Controller implements View.OnClickListener, ToolbarMenuItem.ToolbarMenuItemCallback { |
|
||||||
private static final int OPTION_SORT_A_Z = 1; |
|
||||||
|
|
||||||
@Inject |
|
||||||
BoardManager boardManager; |
|
||||||
|
|
||||||
private RecyclerView recyclerView; |
|
||||||
private BoardEditAdapter adapter; |
|
||||||
private FloatingActionButton add; |
|
||||||
private ItemTouchHelper itemTouchHelper; |
|
||||||
|
|
||||||
private List<Board> boards; |
|
||||||
|
|
||||||
public BoardEditController(Context context) { |
|
||||||
super(context); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onCreate() { |
|
||||||
super.onCreate(); |
|
||||||
getGraph().inject(this); |
|
||||||
|
|
||||||
navigationItem.setTitle(R.string.board_edit); |
|
||||||
|
|
||||||
List<FloatingMenuItem> items = new ArrayList<>(); |
|
||||||
items.add(new FloatingMenuItem(OPTION_SORT_A_Z, R.string.board_edit_sort_a_z)); |
|
||||||
navigationItem.menu = new ToolbarMenu(context); |
|
||||||
navigationItem.createOverflow(context, this, items); |
|
||||||
navigationItem.swipeable = false; |
|
||||||
|
|
||||||
view = inflateRes(R.layout.controller_board_edit); |
|
||||||
recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); |
|
||||||
recyclerView.setHasFixedSize(true); |
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(context)); |
|
||||||
add = (FloatingActionButton) view.findViewById(R.id.add); |
|
||||||
add.setOnClickListener(this); |
|
||||||
theme().applyFabColor(add); |
|
||||||
|
|
||||||
boards = boardManager.getSavedBoards(); |
|
||||||
|
|
||||||
adapter = new BoardEditAdapter(); |
|
||||||
recyclerView.setAdapter(adapter); |
|
||||||
|
|
||||||
itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() { |
|
||||||
@Override |
|
||||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { |
|
||||||
boolean isBoardItem = viewHolder.getAdapterPosition() > 0; |
|
||||||
int dragFlags = isBoardItem ? ItemTouchHelper.UP | ItemTouchHelper.DOWN : 0; |
|
||||||
int swipeFlags = isBoardItem ? ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT : 0; |
|
||||||
return makeMovementFlags(dragFlags, swipeFlags); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { |
|
||||||
int from = viewHolder.getAdapterPosition(); |
|
||||||
int to = target.getAdapterPosition(); |
|
||||||
|
|
||||||
if (to > 0) { |
|
||||||
Board item = boards.remove(from - 1); |
|
||||||
boards.add(to - 1, item); |
|
||||||
adapter.notifyItemMoved(from, to); |
|
||||||
return true; |
|
||||||
} else { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { |
|
||||||
final int position = viewHolder.getAdapterPosition(); |
|
||||||
final Board board = boards.get(position - 1); |
|
||||||
board.saved = false; |
|
||||||
boards.remove(position - 1); |
|
||||||
adapter.notifyItemRemoved(position); |
|
||||||
|
|
||||||
Snackbar snackbar = Snackbar.make(view, context.getString(R.string.board_edit_board_removed, board.name), Snackbar.LENGTH_LONG); |
|
||||||
fixSnackbarText(context, snackbar); |
|
||||||
snackbar.setAction(R.string.undo, new View.OnClickListener() { |
|
||||||
@Override |
|
||||||
public void onClick(View v) { |
|
||||||
board.saved = true; |
|
||||||
boards.add(position - 1, board); |
|
||||||
adapter.notifyDataSetChanged(); |
|
||||||
} |
|
||||||
}); |
|
||||||
snackbar.show(); |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
itemTouchHelper.attachToRecyclerView(recyclerView); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onMenuItemClicked(ToolbarMenuItem item) { |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onSubMenuItemClicked(ToolbarMenuItem parent, FloatingMenuItem item) { |
|
||||||
if (((Integer) item.getId()) == OPTION_SORT_A_Z) { |
|
||||||
Collections.sort(boards, new Comparator<Board>() { |
|
||||||
@Override |
|
||||||
public int compare(Board lhs, Board rhs) { |
|
||||||
return lhs.code.compareTo(rhs.code); |
|
||||||
} |
|
||||||
}); |
|
||||||
adapter.notifyDataSetChanged(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onDestroy() { |
|
||||||
super.onDestroy(); |
|
||||||
|
|
||||||
for (int i = 0; i < boards.size(); i++) { |
|
||||||
boards.get(i).order = i; |
|
||||||
} |
|
||||||
|
|
||||||
// TODO(multisite)
|
|
||||||
// boardManager.flushOrderAndSaved();
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onClick(View v) { |
|
||||||
if (v == add) { |
|
||||||
showAddBoardDialog(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private void showAddBoardDialog() { |
|
||||||
LinearLayout wrap = new LinearLayout(context); |
|
||||||
wrap.setPadding(dp(16), dp(16), dp(16), 0); |
|
||||||
final AutoCompleteTextView text = new AutoCompleteTextView(context); |
|
||||||
text.setSingleLine(); |
|
||||||
wrap.addView(text, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); |
|
||||||
|
|
||||||
FillAdapter fillAdapter = new FillAdapter(context, 0); |
|
||||||
fillAdapter.setEditingList(boards); |
|
||||||
fillAdapter.setAutoCompleteView(text); |
|
||||||
text.setAdapter(fillAdapter); |
|
||||||
text.setThreshold(1); |
|
||||||
text.setDropDownHeight(ViewGroup.LayoutParams.WRAP_CONTENT); |
|
||||||
text.setHint(R.string.board_add_hint); |
|
||||||
text.setImeOptions(EditorInfo.IME_FLAG_NO_FULLSCREEN); |
|
||||||
|
|
||||||
AlertDialog dialog = new AlertDialog.Builder(context) |
|
||||||
.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.toLowerCase(Locale.ENGLISH)); |
|
||||||
} |
|
||||||
} |
|
||||||
}).setNegativeButton(R.string.cancel, null) |
|
||||||
.setTitle(R.string.board_add) |
|
||||||
.setView(wrap) |
|
||||||
.create(); |
|
||||||
|
|
||||||
AndroidUtils.requestKeyboardFocus(dialog, text); |
|
||||||
|
|
||||||
dialog.show(); |
|
||||||
} |
|
||||||
|
|
||||||
private void addBoard(String value) { |
|
||||||
value = value.replace(" ", ""); |
|
||||||
value = value.replace("/", ""); |
|
||||||
value = value.replace("\\", ""); |
|
||||||
|
|
||||||
// Duplicate
|
|
||||||
for (Board board : boards) { |
|
||||||
if (board.code.equals(value)) { |
|
||||||
new AlertDialog.Builder(context).setMessage(R.string.board_add_duplicate).setPositiveButton(R.string.ok, null).show(); |
|
||||||
|
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Normal add
|
|
||||||
List<Board> all = boardManager.getSavedBoards(); |
|
||||||
for (Board board : all) { |
|
||||||
if (board.code.equals(value)) { |
|
||||||
board.saved = true; |
|
||||||
boards.add(board); |
|
||||||
adapter.notifyDataSetChanged(); |
|
||||||
|
|
||||||
recyclerView.smoothScrollToPosition(boards.size()); |
|
||||||
|
|
||||||
Snackbar snackbar = Snackbar.make(view, getString(R.string.board_add_success) + " " + board.name, Snackbar.LENGTH_LONG); |
|
||||||
fixSnackbarText(context, snackbar); |
|
||||||
snackbar.show(); |
|
||||||
|
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
// Unknown
|
|
||||||
new AlertDialog.Builder(context) |
|
||||||
.setTitle(R.string.board_add_unknown_title) |
|
||||||
.setMessage(context.getString(R.string.board_add_unknown, value)) |
|
||||||
.setPositiveButton(R.string.ok, null) |
|
||||||
.show(); |
|
||||||
} |
|
||||||
|
|
||||||
private 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<>(); |
|
||||||
|
|
||||||
public FillAdapter(Context context, int resource) { |
|
||||||
super(context, resource); |
|
||||||
|
|
||||||
filter = new Filter() { |
|
||||||
@Override |
|
||||||
protected synchronized FilterResults performFiltering(CharSequence constraint) { |
|
||||||
FilterResults results = new FilterResults(); |
|
||||||
|
|
||||||
if (TextUtils.isEmpty(constraint) || (constraint.toString().startsWith(" "))) { |
|
||||||
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(); |
|
||||||
} |
|
||||||
}; |
|
||||||
} |
|
||||||
|
|
||||||
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).code; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public View getView(int position, View convertView, ViewGroup parent) { |
|
||||||
@SuppressLint("ViewHolder") |
|
||||||
TextView view = (TextView) LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false); |
|
||||||
Board b = filtered.get(position); |
|
||||||
view.setText("/" + b.code + "/ - " + b.name); |
|
||||||
|
|
||||||
view.setOnTouchListener(new View.OnTouchListener() { |
|
||||||
@Override |
|
||||||
public boolean onTouch(View v, MotionEvent event) { |
|
||||||
if (event.getAction() == MotionEvent.ACTION_DOWN) { |
|
||||||
AndroidUtils.hideKeyboard(autoCompleteView); |
|
||||||
} |
|
||||||
|
|
||||||
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<>(); |
|
||||||
for (Board b : getBoards()) { |
|
||||||
if ((b.name.toLowerCase(Locale.ENGLISH).contains(lowered) || b.code.toLowerCase(Locale.ENGLISH) |
|
||||||
.contains(lowered))) { |
|
||||||
list.add(b); |
|
||||||
} |
|
||||||
} |
|
||||||
return list; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean haveBoard(String value) { |
|
||||||
for (Board b : currentlyEditing) { |
|
||||||
if (b.code.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, hide them otherwise.
|
|
||||||
/*boolean showUnsafe = false; |
|
||||||
for (Board has : currentlyEditing) { |
|
||||||
if (!has.workSafe) { |
|
||||||
showUnsafe = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
}*/ |
|
||||||
List<Board> s = new ArrayList<>(); |
|
||||||
for (Board b : boardManager.getSavedBoards()) { |
|
||||||
if (!haveBoard(b.code)/* && (showUnsafe || b.workSafe)*/) { |
|
||||||
s.add(b); |
|
||||||
} |
|
||||||
} |
|
||||||
return s; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class BoardEditAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { |
|
||||||
private int TYPE_ITEM = 0; |
|
||||||
private int TYPE_HEADER = 1; |
|
||||||
|
|
||||||
public BoardEditAdapter() { |
|
||||||
setHasStableIds(true); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { |
|
||||||
if (viewType == TYPE_ITEM) { |
|
||||||
return new BoardEditItem(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_board_edit, parent, false)); |
|
||||||
} else { |
|
||||||
return new BoardEditHeader(LayoutInflater.from(parent.getContext()).inflate(R.layout.cell_board_edit_header, parent, false)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { |
|
||||||
if (getItemViewType(position) == TYPE_HEADER) { |
|
||||||
BoardEditHeader header = (BoardEditHeader) holder; |
|
||||||
header.text.setText(R.string.board_edit_header); |
|
||||||
} else { |
|
||||||
BoardEditItem item = (BoardEditItem) holder; |
|
||||||
Board board = boards.get(position - 1); |
|
||||||
item.text.setText(BoardHelper.getName(board)); |
|
||||||
item.description.setText(BoardHelper.getDescription(board)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemViewType(int position) { |
|
||||||
return position == 0 ? TYPE_HEADER : TYPE_ITEM; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getItemCount() { |
|
||||||
return boards.size() + 1; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public long getItemId(int position) { |
|
||||||
if (getItemViewType(position) == TYPE_HEADER) { |
|
||||||
return -1; |
|
||||||
} else { |
|
||||||
return boards.get(position - 1).id; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class BoardEditItem extends RecyclerView.ViewHolder { |
|
||||||
private ImageView thumb; |
|
||||||
private TextView text; |
|
||||||
private TextView description; |
|
||||||
|
|
||||||
public BoardEditItem(View itemView) { |
|
||||||
super(itemView); |
|
||||||
thumb = (ImageView) itemView.findViewById(R.id.thumb); |
|
||||||
text = (TextView) itemView.findViewById(R.id.text); |
|
||||||
description = (TextView) itemView.findViewById(R.id.description); |
|
||||||
|
|
||||||
thumb.setOnTouchListener(new View.OnTouchListener() { |
|
||||||
public boolean onTouch(View v, MotionEvent event) { |
|
||||||
if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { |
|
||||||
itemTouchHelper.startDrag(BoardEditItem.this); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
}); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private class BoardEditHeader extends RecyclerView.ViewHolder { |
|
||||||
private TextView text; |
|
||||||
|
|
||||||
public BoardEditHeader(View itemView) { |
|
||||||
super(itemView); |
|
||||||
text = (TextView) itemView.findViewById(R.id.text); |
|
||||||
text.setTypeface(AndroidUtils.ROBOTO_MEDIUM_ITALIC); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,237 @@ |
|||||||
|
/* |
||||||
|
* 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.layout; |
||||||
|
|
||||||
|
import android.annotation.SuppressLint; |
||||||
|
import android.graphics.drawable.Drawable; |
||||||
|
import android.util.Pair; |
||||||
|
import android.view.Gravity; |
||||||
|
import android.view.LayoutInflater; |
||||||
|
import android.view.View; |
||||||
|
import android.view.ViewGroup; |
||||||
|
import android.widget.AdapterView; |
||||||
|
import android.widget.BaseAdapter; |
||||||
|
import android.widget.ImageView; |
||||||
|
import android.widget.TextView; |
||||||
|
|
||||||
|
import org.floens.chan.R; |
||||||
|
import org.floens.chan.core.manager.BoardManager; |
||||||
|
import org.floens.chan.core.model.orm.Board; |
||||||
|
import org.floens.chan.core.site.Site; |
||||||
|
import org.floens.chan.core.site.SiteIcon; |
||||||
|
import org.floens.chan.ui.helper.BoardHelper; |
||||||
|
import org.floens.chan.ui.view.FloatingMenu; |
||||||
|
import org.floens.chan.utils.AndroidUtils; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Observable; |
||||||
|
import java.util.Observer; |
||||||
|
|
||||||
|
import static org.floens.chan.utils.AndroidUtils.dp; |
||||||
|
|
||||||
|
public class BrowseBoardsFloatingMenu implements Observer, AdapterView.OnItemClickListener { |
||||||
|
private FloatingMenu floatingMenu; |
||||||
|
private BoardManager.SavedBoards savedBoards; |
||||||
|
private BrowseBoardsAdapter adapter; |
||||||
|
|
||||||
|
private Callback callback; |
||||||
|
|
||||||
|
public BrowseBoardsFloatingMenu(BoardManager.SavedBoards savedBoards) { |
||||||
|
this.savedBoards = savedBoards; |
||||||
|
this.savedBoards.addObserver(this); |
||||||
|
} |
||||||
|
|
||||||
|
private void onDismissed() { |
||||||
|
savedBoards.deleteObserver(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void setCallback(Callback callback) { |
||||||
|
this.callback = callback; |
||||||
|
} |
||||||
|
|
||||||
|
public void show(View anchor, Board selectedBoard) { |
||||||
|
floatingMenu = new FloatingMenu(anchor.getContext()); |
||||||
|
floatingMenu.setCallback(new FloatingMenu.FloatingMenuCallbackAdapter() { |
||||||
|
@Override |
||||||
|
public void onFloatingMenuDismissed(FloatingMenu menu) { |
||||||
|
onDismissed(); |
||||||
|
} |
||||||
|
}); |
||||||
|
floatingMenu.setManageItems(false); |
||||||
|
floatingMenu.setAnchor(anchor, Gravity.LEFT, dp(5), dp(5)); |
||||||
|
floatingMenu.setPopupWidth(FloatingMenu.POPUP_WIDTH_ANCHOR); |
||||||
|
adapter = new BrowseBoardsAdapter(); |
||||||
|
floatingMenu.setAdapter(adapter); |
||||||
|
floatingMenu.setOnItemClickListener(this); |
||||||
|
floatingMenu.setSelectedPosition(resolveCurrentIndex(selectedBoard)); |
||||||
|
floatingMenu.show(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void update(Observable o, Object arg) { |
||||||
|
if (o == savedBoards) { |
||||||
|
adapter.notifyDataSetChanged(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { |
||||||
|
Pair<Site, Board> siteOrBoard = getAtPosition(position); |
||||||
|
if (siteOrBoard.second != null) { |
||||||
|
callback.onBoardClicked(siteOrBoard.second); |
||||||
|
} else { |
||||||
|
callback.onSiteClicked(siteOrBoard.first); |
||||||
|
} |
||||||
|
floatingMenu.dismiss(); |
||||||
|
} |
||||||
|
|
||||||
|
private int getCount() { |
||||||
|
int count = 0; |
||||||
|
for (Pair<Site, List<Board>> siteListPair : savedBoards.get()) { |
||||||
|
count += 1; |
||||||
|
count += siteListPair.second.size(); |
||||||
|
} |
||||||
|
|
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
private int resolveCurrentIndex(Board board) { |
||||||
|
int position = 0; |
||||||
|
for (Pair<Site, List<Board>> siteListPair : savedBoards.get()) { |
||||||
|
position += 1; |
||||||
|
|
||||||
|
for (Board other : siteListPair.second) { |
||||||
|
if (board == other) { |
||||||
|
return position; |
||||||
|
} |
||||||
|
position++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
private Pair<Site, Board> getAtPosition(int position) { |
||||||
|
for (Pair<Site, List<Board>> siteListPair : savedBoards.get()) { |
||||||
|
if (position == 0) { |
||||||
|
return new Pair<>(siteListPair.first, null); |
||||||
|
} |
||||||
|
position -= 1; |
||||||
|
|
||||||
|
if (position < siteListPair.second.size()) { |
||||||
|
return new Pair<>(null, siteListPair.second.get(position)); |
||||||
|
} |
||||||
|
position -= siteListPair.second.size(); |
||||||
|
} |
||||||
|
throw new IllegalArgumentException(); |
||||||
|
} |
||||||
|
|
||||||
|
private class BrowseBoardsAdapter extends BaseAdapter { |
||||||
|
final int TYPE_SITE = 0; |
||||||
|
final int TYPE_BOARD = 1; |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getViewTypeCount() { |
||||||
|
return 2; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getItemViewType(int position) { |
||||||
|
Pair<Site, Board> siteOrBoard = getAtPosition(position); |
||||||
|
if (siteOrBoard.first != null) { |
||||||
|
return TYPE_SITE; |
||||||
|
} else if (siteOrBoard.second != null) { |
||||||
|
return TYPE_BOARD; |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int getCount() { |
||||||
|
return BrowseBoardsFloatingMenu.this.getCount(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Object getItem(int position) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public long getItemId(int position) { |
||||||
|
return position; |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("ViewHolder") |
||||||
|
@Override |
||||||
|
public View getView(int position, View view, ViewGroup parent) { |
||||||
|
LayoutInflater inflater = LayoutInflater.from(parent.getContext()); |
||||||
|
|
||||||
|
Pair<Site, Board> siteOrBoard = getAtPosition(position); |
||||||
|
if (siteOrBoard.first != null) { |
||||||
|
Site site = siteOrBoard.first; |
||||||
|
|
||||||
|
if (view == null) { |
||||||
|
view = inflater.inflate(R.layout.cell_browse_site, parent, false); |
||||||
|
} |
||||||
|
|
||||||
|
View divider = view.findViewById(R.id.divider); |
||||||
|
final ImageView image = view.findViewById(R.id.image); |
||||||
|
TextView text = view.findViewById(R.id.text); |
||||||
|
|
||||||
|
divider.setVisibility(position == 0 ? View.GONE : View.VISIBLE); |
||||||
|
|
||||||
|
final SiteIcon icon = site.icon(); |
||||||
|
image.setTag(icon); |
||||||
|
|
||||||
|
icon.get(new SiteIcon.SiteIconResult() { |
||||||
|
@Override |
||||||
|
public void onSiteIcon(SiteIcon siteIcon, Drawable drawable) { |
||||||
|
if (image.getTag() == icon) { |
||||||
|
image.setImageDrawable(drawable); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
text.setTypeface(AndroidUtils.ROBOTO_MEDIUM); |
||||||
|
text.setText(site.name()); |
||||||
|
|
||||||
|
return view; |
||||||
|
} else { |
||||||
|
Board board = siteOrBoard.second; |
||||||
|
|
||||||
|
if (view == null) { |
||||||
|
view = inflater.inflate(R.layout.cell_browse_board, parent, false); |
||||||
|
} |
||||||
|
|
||||||
|
TextView text = (TextView) view; |
||||||
|
|
||||||
|
text.setTypeface(AndroidUtils.ROBOTO_MEDIUM); |
||||||
|
text.setText(BoardHelper.getName(board)); |
||||||
|
|
||||||
|
return text; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public interface Callback { |
||||||
|
void onBoardClicked(Board item); |
||||||
|
|
||||||
|
void onSiteClicked(Site site); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
/* |
||||||
|
* 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.toolbar; |
||||||
|
|
||||||
|
import android.view.View; |
||||||
|
|
||||||
|
public interface ToolbarMiddleMenu { |
||||||
|
void show(View anchor); |
||||||
|
} |
@ -1,69 +0,0 @@ |
|||||||
<?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="wrap_content" |
|
||||||
android:background="?attr/selectableItemBackground" |
|
||||||
android:orientation="horizontal"> |
|
||||||
|
|
||||||
<ImageView |
|
||||||
android:id="@+id/thumb" |
|
||||||
android:layout_width="56dp" |
|
||||||
android:layout_height="match_parent" |
|
||||||
android:layout_gravity="center_vertical" |
|
||||||
android:paddingLeft="8dp" |
|
||||||
android:paddingRight="8dp" |
|
||||||
android:scaleType="center" |
|
||||||
android:src="@drawable/ic_reorder_black_24dp" |
|
||||||
tools:ignore="ContentDescription" /> |
|
||||||
|
|
||||||
<LinearLayout |
|
||||||
android:layout_width="0dp" |
|
||||||
android:layout_height="match_parent" |
|
||||||
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" |
|
||||||
tools:text="Technology" /> |
|
||||||
|
|
||||||
<TextView |
|
||||||
android:id="@+id/description" |
|
||||||
android:layout_width="match_parent" |
|
||||||
android:layout_height="wrap_content" |
|
||||||
android:ellipsize="end" |
|
||||||
android:paddingBottom="8dp" |
|
||||||
android:paddingLeft="16dp" |
|
||||||
android:paddingRight="16dp" |
|
||||||
android:textColor="?text_color_secondary" |
|
||||||
android:textSize="12sp" |
|
||||||
tools:text="Description is here" /> |
|
||||||
|
|
||||||
</LinearLayout> |
|
||||||
|
|
||||||
</LinearLayout> |
|
@ -0,0 +1,55 @@ |
|||||||
|
<?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/>. |
||||||
|
--> |
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="horizontal" |
||||||
|
tools:ignore="RtlHardcoded"> |
||||||
|
|
||||||
|
<View |
||||||
|
android:id="@+id/divider" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="1dp" |
||||||
|
android:background="?attr/divider_color" /> |
||||||
|
|
||||||
|
<ImageView |
||||||
|
android:id="@+id/image" |
||||||
|
android:layout_width="48dp" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:paddingBottom="8dp" |
||||||
|
android:paddingLeft="16dp" |
||||||
|
android:paddingTop="8dp" |
||||||
|
android:scaleType="fitCenter" |
||||||
|
tools:src="@drawable/ic_help_outline_black_24dp" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/text" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="48dp" |
||||||
|
android:ellipsize="end" |
||||||
|
android:gravity="center_vertical" |
||||||
|
android:lines="1" |
||||||
|
android:paddingLeft="56dp" |
||||||
|
android:paddingRight="8dp" |
||||||
|
android:singleLine="true" |
||||||
|
android:textColor="?text_color_primary" |
||||||
|
android:textSize="16sp" |
||||||
|
tools:text="Site name" /> |
||||||
|
|
||||||
|
</FrameLayout> |
Loading…
Reference in new issue