Revamp BookmarksActivity

This commit is contained in:
Abdul Wadood 2018-07-11 03:58:51 +05:30 committed by Isaac Hutt
parent 8861559097
commit 6fb85b8ddb
32 changed files with 727 additions and 700 deletions

View File

@ -24,9 +24,12 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.yahoo.squidb.data.SquidCursor;
import com.yahoo.squidb.sql.Query;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.kiwix.kiwixmobile.data.local.dao.BookmarksDao;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import java.io.BufferedWriter;
import java.io.File;
@ -38,36 +41,46 @@ import java.util.ArrayList;
import static org.junit.Assert.assertArrayEquals;
@RunWith(AndroidJUnit4.class)
@SmallTest
public class KiwixDatabaseTest {
private Context mContext;
private final Context context;
public KiwixDatabaseTest (){
mContext = InstrumentationRegistry.getTargetContext();
public KiwixDatabaseTest() {
context = InstrumentationRegistry.getTargetContext();
}
@Test
public void testMigrateDatabase() throws IOException {
KiwixDatabase kiwixDatabase = new KiwixDatabase(mContext);
KiwixDatabase kiwixDatabase = new KiwixDatabase(context);
kiwixDatabase.recreate();
String testId = "8ce5775a-10a9-bbf3-178a-9df69f23263c";
String[] testBookmarks = new String[] {"Test1","Test2","Test3"};
String fileName = mContext.getFilesDir().getAbsolutePath() + File.separator + testId + ".txt";
String[] testBookmarks = new String[]{"Test1", "Test2", "Test3"};
String fileName = context.getFilesDir().getAbsolutePath() + File.separator + testId + ".txt";
File f = new File(fileName);
f.createNewFile();
if (!f.createNewFile()) {
throw new IOException("Unable to create file for testing migration");
}
Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), "utf-8"));
for (String bookmark : testBookmarks){
for (String bookmark : testBookmarks) {
writer.write(bookmark + "\n");
}
writer.close();
kiwixDatabase.migrateBookmarksVersion6();
kiwixDatabase.migrateBookmarks();
BookmarksDao bookmarksDao = new BookmarksDao(kiwixDatabase);
ArrayList<String> b = bookmarksDao.getBookmarkTitles(testId, "");
assertArrayEquals(testBookmarks,b.toArray());
ArrayList<String> bookmarkTitles = new ArrayList<>();
try (SquidCursor<Bookmark> bookmarkCursor = kiwixDatabase.query(Bookmark.class,
Query.selectDistinct(Bookmark.BOOKMARK_TITLE)
.where(Bookmark.ZIM_ID.eq(testId)
.or(Bookmark.ZIM_NAME.eq("")))
.orderBy(Bookmark.BOOKMARK_TITLE.asc()))) {
while (bookmarkCursor.moveToNext()) {
bookmarkTitles.add(bookmarkCursor.get(Bookmark.BOOKMARK_TITLE));
}
}
assertArrayEquals(testBookmarks, bookmarkTitles.toArray());
// TODO Add new migration test for version 16
}
}

View File

@ -1,243 +1,59 @@
/*
* Copyright 2013 Elad Keyshawn <elad.keyshawn@gmail.com>
*
* 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
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
package org.kiwix.kiwixmobile.bookmark;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ImageView;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.base.BaseActivity;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.main.MainActivity;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.N;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_BOOKMARK_CLICKED;
import static org.kiwix.kiwixmobile.library.LibraryAdapter.createBitmapFromEncodedString;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_CHOSE_X_TITLE;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_CHOSE_X_URL;
public class BookmarksActivity extends BaseActivity
implements AdapterView.OnItemClickListener, BookmarksViewCallback {
public class BookmarksActivity extends BaseActivity implements BookmarksContract.View,
BookmarksAdapter.OnItemClickListener {
private ArrayList<String> bookmarks;
private ArrayList<String> bookmarkUrls;
@BindView(R.id.bookmarks_list)
ListView bookmarksList;
private BookmarksArrayAdapter adapter;
@BindView(R.id.bookmarks_activity_layout)
CoordinatorLayout snackbarLayout;
@BindView(R.id.bookmarks_none_linlayout)
LinearLayout noBookmarksLayout;
private final List<Bookmark> bookmarksList = new ArrayList<>();
private final List<Bookmark> allBookmarks = new ArrayList<>();
private final List<Bookmark> deleteList = new ArrayList<>();
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@Inject
BookmarksPresenter presenter;
private ActionModeListener actionModeListener;
BookmarksContract.Presenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bookmarks);
ButterKnife.bind(this);
setUpToolbar();
bookmarks = new ArrayList<>();
bookmarkUrls = new ArrayList<>();
actionModeListener = new ActionModeListener();
adapter = new BookmarksArrayAdapter(getApplicationContext(), R.layout.bookmarks_row, R.id.bookmark_title, bookmarks);
bookmarksList.setAdapter(adapter);
bookmarksList.setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE_MODAL);
bookmarksList.setMultiChoiceModeListener(actionModeListener);
bookmarksList.setOnItemClickListener(this);
presenter.attachView(this);
presenter.loadBookmarks();
}
private void setNoBookmarksState() {
if (bookmarksList.getCount() == 0) {
noBookmarksLayout.setVisibility(View.VISIBLE);
} else {
noBookmarksLayout.setVisibility(View.GONE);
}
}
private void deleteSelectedItems() {
SparseBooleanArray sparseBooleanArray = bookmarksList.getCheckedItemPositions();
for (int i = sparseBooleanArray.size() - 1; i >= 0; i--) {
deleteBookmark(bookmarkUrls.get(sparseBooleanArray.keyAt(i)));
bookmarks.remove(sparseBooleanArray.keyAt(i));
bookmarkUrls.remove(sparseBooleanArray.keyAt(i));
}
adapter.notifyDataSetChanged();
setNoBookmarksState();
}
private void deleteBookmark(String article) {
presenter.deleteBookmark(article);
}
private void setUpToolbar() {
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(getString(R.string.menu_bookmarks_list));
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(v -> onBackPressed());
}
public ArrayList<String> stripHtml(ArrayList<String> html) {
ArrayList<String> parsed = new ArrayList<>();
if (SDK_INT >= N) {
for (int i = 0; i < html.size(); i++) {
parsed.add(i, Html.fromHtml(html.get(i), Html.FROM_HTML_MODE_LEGACY).toString());
}
} else {
for (int i = 0; i < html.size(); i++) {
parsed.add(i, Html.fromHtml(html.get(i)).toString());
}
}
return parsed;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(this, MainActivity.class);
if (!bookmarkUrls.get(position).equals("null")) {
intent.putExtra(EXTRA_CHOSE_X_URL, bookmarkUrls.get(position));
} else {
intent.putExtra(EXTRA_CHOSE_X_TITLE, bookmarks.get(position));
}
intent.putExtra(EXTRA_BOOKMARK_CLICKED, true);
int value = Settings.System.getInt(getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0);
if (value == 1) {
startActivity(intent);
finish();
} else {
setResult(RESULT_OK, intent);
finish();
}
}
@Override
public void onBackPressed() {
int value = Settings.System.getInt(getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0);
Intent startIntent = new Intent(this, MainActivity.class);
startIntent.putExtra(EXTRA_BOOKMARK_CLICKED, false);
if (value == 1) { // means there's only 1 activity in stack so start new
startActivity(startIntent);
} else { // we have a parent activity waiting...
setResult(RESULT_OK, startIntent);
finish();
}
}
@Override
public void showBookmarks(ArrayList<String> bookmarks, ArrayList<String> bookmarkUrls) {
this.bookmarks.clear();
this.bookmarkUrls.clear();
ArrayList<String> parsedBookmarks = new ArrayList<>();
parsedBookmarks = stripHtml(bookmarks);
this.bookmarks.addAll(parsedBookmarks);
this.bookmarkUrls.addAll(bookmarkUrls);
adapter.notifyDataSetChanged();
setNoBookmarksState();
}
@Override
public void popDeleteBookmarksSnackbar() {
Snackbar bookmarkDeleteSnackbar =
Snackbar.make(snackbarLayout, actionModeListener.getNumOfSelected() + " " + getString(R.string.deleted_message), Snackbar.LENGTH_LONG);
bookmarkDeleteSnackbar.setActionTextColor(getResources().getColor(R.color.white));
bookmarkDeleteSnackbar.show();
}
class ActionModeListener implements AbsListView.MultiChoiceModeListener {
private ArrayList<String> selected = new ArrayList<>();
private int numOfSelected = 0;
public ActionModeListener() {
}
public int getNumOfSelected() {
return numOfSelected;
}
@Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
if (checked) {
selected.add(bookmarks.get(position));
numOfSelected++;
mode.setTitle(Integer.toString(numOfSelected));
} else if (selected.contains(bookmarks.get(position))) {
selected.remove(bookmarks.get(position));
numOfSelected--;
if (numOfSelected == 0) {
mode.finish();
} else {
mode.setTitle(Integer.toString(numOfSelected));
}
}
}
private boolean refreshAdapter = true;
private BookmarksAdapter bookmarksAdapter;
private ActionMode actionMode;
private final ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.menu_bookmarks, menu);
numOfSelected = 0;
mode.getMenuInflater().inflate(R.menu.menu_context_delete, menu);
return true;
}
@ -248,40 +64,166 @@ public class BookmarksActivity extends BaseActivity
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
refreshAdapter = false;
switch (item.getItemId()) {
case R.id.menu_bookmarks_delete:
deleteSelectedItems();
popDeleteBookmarksSnackbar();
case R.id.menu_context_delete:
allBookmarks.removeAll(deleteList);
for (Bookmark bookmark : deleteList) {
int position = bookmarksList.indexOf(bookmark);
bookmarksList.remove(bookmark);
bookmarksAdapter.notifyItemRemoved(position);
bookmarksAdapter.notifyItemRangeChanged(position, bookmarksAdapter.getItemCount());
}
mode.finish();
return true;
default:
return false;
}
return false;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
}
}
class BookmarksArrayAdapter extends ArrayAdapter<String> {
public BookmarksArrayAdapter(Context context, int resource, int textViewResourceId, List<String> objects) {
super(context, resource, textViewResourceId, objects);
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflater = getLayoutInflater();
convertView = inflater.inflate(R.layout.bookmarks_row, null);
if (deleteList.size() != 0) {
presenter.deleteBookmarks(new ArrayList<>(deleteList));
deleteList.clear();
}
return super.getView(position, convertView, parent);
actionMode = null;
if (refreshAdapter) {
bookmarksAdapter.notifyDataSetChanged();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter.attachView(this);
setContentView(R.layout.activity_bookmarks_history_language);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.menu_bookmarks);
}
bookmarksAdapter = new BookmarksAdapter(bookmarksList, deleteList, this);
recyclerView.setAdapter(bookmarksAdapter);
}
@Override
protected void onResume() {
super.onResume();
presenter.loadBookmarks(sharedPreferenceUtil.getShowBookmarksCurrentBook());
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_bookmarks, menu);
MenuItem toggle = menu.findItem(R.id.menu_bookmarks_toggle);
toggle.setChecked(sharedPreferenceUtil.getShowBookmarksCurrentBook());
SearchView search = (SearchView) menu.findItem(R.id.menu_bookmarks_search).getActionView();
search.setQueryHint(getString(R.string.search_bookmarks));
search.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String newText) {
bookmarksList.clear();
bookmarksList.addAll(allBookmarks);
if ("".equals(newText)) {
bookmarksAdapter.notifyDataSetChanged();
return true;
}
presenter.filterBookmarks(bookmarksList, newText);
return true;
}
});
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
case R.id.menu_bookmarks_toggle:
item.setChecked(!item.isChecked());
sharedPreferenceUtil.setShowBookmarksCurrentBook(item.isChecked());
presenter.loadBookmarks(sharedPreferenceUtil.getShowBookmarksCurrentBook());
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
presenter.detachView();
super.onDestroy();
}
@Override
public void updateBookmarksList(List<Bookmark> bookmarksList) {
allBookmarks.clear();
allBookmarks.addAll(bookmarksList);
notifyBookmarksListFiltered(bookmarksList);
}
@Override
public void notifyBookmarksListFiltered(List<Bookmark> bookmarksList) {
this.bookmarksList.clear();
this.bookmarksList.addAll(bookmarksList);
bookmarksAdapter.notifyDataSetChanged();
}
@Override
public void onItemClick(ImageView favicon, Bookmark bookmark) {
if (actionMode == null) {
Intent intent = new Intent(this, MainActivity.class);
if ("null".equals(bookmark.getBookmarkUrl())) {
intent.putExtra(EXTRA_CHOSE_X_TITLE, bookmark.getBookmarkTitle());
} else {
intent.putExtra(EXTRA_CHOSE_X_URL, bookmark.getBookmarkUrl());
}
if (bookmark.getZimFilePath() != null && !bookmark.getZimFilePath().equals(ZimContentProvider.getZimFile())) {
intent.setData(Uri.fromFile(new File(bookmark.getZimFilePath())));
}
if (Settings.System.getInt(getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) == 1) {
startActivity(intent);
} else {
setResult(RESULT_OK, intent);
}
finish();
} else {
toggleSelection(favicon, bookmark);
}
}
@Override
public boolean onItemLongClick(ImageView favicon, Bookmark bookmark) {
if (actionMode != null) {
return false;
}
actionMode = startSupportActionMode(actionModeCallback);
refreshAdapter = true;
toggleSelection(favicon, bookmark);
return true;
}
private void toggleSelection(ImageView favicon, Bookmark bookmark) {
if (deleteList.remove(bookmark)) {
favicon.setImageBitmap(createBitmapFromEncodedString(bookmark.getFavicon(), this));
} else {
favicon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_check_circle_blue_24dp));
deleteList.add(bookmark);
}
actionMode.setTitle(getString(R.string.selected_items, deleteList.size()));
if (deleteList.size() == 0) {
actionMode.finish();
}
}
}

View File

@ -0,0 +1,79 @@
package org.kiwix.kiwixmobile.bookmark;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import static org.kiwix.kiwixmobile.library.LibraryAdapter.createBitmapFromEncodedString;
class BookmarksAdapter extends RecyclerView.Adapter<BookmarksAdapter.Item> {
private final List<Bookmark> bookmarkList;
private final OnItemClickListener itemClickListener;
private final List<Bookmark> deleteList;
BookmarksAdapter(List<Bookmark> bookmarkList, List<Bookmark> deleteList, OnItemClickListener itemClickListener) {
this.bookmarkList = bookmarkList;
this.deleteList = deleteList;
this.itemClickListener = itemClickListener;
}
@NonNull
@Override
public Item onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bookmark_history, parent, false);
return new Item(view);
}
@Override
public void onBindViewHolder(@NonNull Item holder, int position) {
Bookmark bookmark = bookmarkList.get(position);
holder.title.setText(bookmark.getBookmarkTitle());
if (deleteList.contains(bookmark)) {
holder.favicon.setImageDrawable(ContextCompat.getDrawable(holder.favicon.getContext(),
R.drawable.ic_check_circle_blue_24dp));
} else {
holder.favicon.setImageBitmap(createBitmapFromEncodedString(bookmark.getFavicon(),
holder.favicon.getContext()));
}
holder.itemView.setOnClickListener(v -> itemClickListener.onItemClick(holder.favicon, bookmark));
holder.itemView.setOnLongClickListener(v ->
itemClickListener.onItemLongClick(holder.favicon, bookmark));
}
@Override
public int getItemCount() {
return bookmarkList.size();
}
interface OnItemClickListener {
void onItemClick(ImageView favicon, Bookmark bookmark);
boolean onItemLongClick(ImageView favicon, Bookmark bookmark);
}
class Item extends RecyclerView.ViewHolder {
@BindView(R.id.favicon)
ImageView favicon;
@BindView(R.id.title)
TextView title;
Item(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

View File

@ -0,0 +1,22 @@
package org.kiwix.kiwixmobile.bookmark;
import org.kiwix.kiwixmobile.base.BaseContract;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import java.util.List;
interface BookmarksContract {
interface View extends BaseContract.View<Presenter> {
void updateBookmarksList(List<Bookmark> bookmarks);
void notifyBookmarksListFiltered(List<Bookmark> bookmarks);
}
interface Presenter extends BaseContract.Presenter<View> {
void loadBookmarks(boolean showBookmarksCurrentBook);
void filterBookmarks(List<Bookmark> bookmarksList, String newText);
void deleteBookmarks(List<Bookmark> deleteList);
}
}

View File

@ -0,0 +1,15 @@
package org.kiwix.kiwixmobile.bookmark;
import org.kiwix.kiwixmobile.di.PerActivity;
import dagger.Module;
import dagger.Provides;
@Module
public class BookmarksModule {
@PerActivity
@Provides
BookmarksContract.Presenter provideBookmarksPresenter(BookmarksPresenter presenter) {
return presenter;
}
}

View File

@ -1,56 +1,108 @@
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* 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.kiwix.kiwixmobile.bookmark;
import org.kiwix.kiwixmobile.base.BasePresenter;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.dao.BookmarksDao;
import android.util.Log;
import java.util.ArrayList;
import org.kiwix.kiwixmobile.base.BasePresenter;
import org.kiwix.kiwixmobile.data.DataSource;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.di.PerActivity;
import org.kiwix.kiwixmobile.di.qualifiers.Computation;
import org.kiwix.kiwixmobile.di.qualifiers.MainThread;
import java.util.List;
import javax.inject.Inject;
/**
* Created by EladKeyshawn on 05/04/2017.
*/
public class BookmarksPresenter extends BasePresenter<BookmarksViewCallback> {
import io.reactivex.CompletableObserver;
import io.reactivex.Observable;
import io.reactivex.Scheduler;
import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
@PerActivity
class BookmarksPresenter extends BasePresenter<BookmarksContract.View> implements BookmarksContract.Presenter {
private final DataSource dataSource;
private final Scheduler mainThread;
private final Scheduler computation;
private Disposable disposable;
@Inject
BookmarksDao bookmarksDao;
@Inject
BookmarksPresenter() {
}
public void loadBookmarks() {
ArrayList<String> bookmarks = bookmarksDao.getBookmarkTitles(ZimContentProvider.getId(), ZimContentProvider.getName());
ArrayList<String> bookmarkUrls = bookmarksDao.getBookmarks(ZimContentProvider.getId(), ZimContentProvider.getName());
view.showBookmarks(bookmarks, bookmarkUrls);
}
public void deleteBookmark(String article) {
bookmarksDao.deleteBookmark(article, ZimContentProvider.getId(), ZimContentProvider.getName());
BookmarksPresenter(DataSource dataSource, @MainThread Scheduler mainThread,
@Computation Scheduler computation) {
this.dataSource = dataSource;
this.mainThread = mainThread;
this.computation = computation;
}
@Override
public void attachView(BookmarksViewCallback mvpView) {
super.attachView(mvpView);
public void loadBookmarks(boolean showFromCurrentBookmarks) {
dataSource.getBookmarks(showFromCurrentBookmarks)
.subscribe(new SingleObserver<List<Bookmark>>() {
@Override
public void onSubscribe(Disposable d) {
if (disposable != null && !disposable.isDisposed()) {
disposable.dispose();
}
disposable = d;
compositeDisposable.add(d);
}
@Override
public void onSuccess(List<Bookmark> bookmarks) {
view.updateBookmarksList(bookmarks);
}
@Override
public void onError(Throwable e) {
Log.e("BookmarksPresenter", e.toString());
}
});
}
@Override
public void filterBookmarks(List<Bookmark> bookmarks, String newText) {
Observable.fromIterable(bookmarks)
.filter(bookmark -> bookmark.getBookmarkTitle().toLowerCase().contains(newText.toLowerCase()))
.toList()
.subscribeOn(computation)
.observeOn(mainThread)
.subscribe(new SingleObserver<List<Bookmark>>() {
@Override
public void onSubscribe(Disposable d) {
compositeDisposable.add(d);
}
@Override
public void onSuccess(List<Bookmark> bookmarkList) {
view.notifyBookmarksListFiltered(bookmarkList);
}
@Override
public void onError(Throwable e) {
Log.e("BookmarksPresenter", e.toString());
}
});
}
@Override
public void deleteBookmarks(List<Bookmark> deleteList) {
dataSource.deleteBookmarks(deleteList)
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
Log.e("BookmarksPresenter", e.toString());
}
});
}
}

View File

@ -1,32 +0,0 @@
/*
* Kiwix Android
* Copyright (C) 2018 Kiwix <android.kiwix.org>
*
* 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.kiwix.kiwixmobile.bookmark;
import org.kiwix.kiwixmobile.base.BaseContract;
import java.util.ArrayList;
/**
* Created by EladKeyshawn on 05/04/2017.
*/
public interface BookmarksViewCallback extends BaseContract.View {
void showBookmarks(ArrayList<String> bookmarks, ArrayList<String> bookmarkUrls);
void popDeleteBookmarksSnackbar();
}

View File

@ -1,5 +1,6 @@
package org.kiwix.kiwixmobile.data;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import org.kiwix.kiwixmobile.models.Language;
@ -27,4 +28,14 @@ public interface DataSource {
Completable deleteHistory(List<History> historyList);
Completable clearHistory();
Single<List<Bookmark>> getBookmarks(boolean showFromCurrentBook);
Single<List<String>> getCurrentZimBookmarksUrl();
Completable saveBookmark(Bookmark bookmark);
Completable deleteBookmarks(List<Bookmark> bookmarks);
Completable deleteBookmark(Bookmark bookmark);
}

View File

@ -1,9 +1,11 @@
package org.kiwix.kiwixmobile.data;
import org.kiwix.kiwixmobile.data.local.dao.BookDao;
import org.kiwix.kiwixmobile.data.local.dao.BookmarksDao;
import org.kiwix.kiwixmobile.data.local.dao.HistoryDao;
import org.kiwix.kiwixmobile.data.local.dao.NetworkLanguageDao;
import org.kiwix.kiwixmobile.data.local.dao.RecentSearchDao;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.di.qualifiers.IO;
import org.kiwix.kiwixmobile.di.qualifiers.MainThread;
@ -30,6 +32,7 @@ import io.reactivex.Single;
public class Repository implements DataSource {
private final BookDao bookDao;
private final BookmarksDao bookmarksDao;
private final HistoryDao historyDao;
private final NetworkLanguageDao languageDao;
private final RecentSearchDao recentSearchDao;
@ -39,6 +42,7 @@ public class Repository implements DataSource {
@Inject
Repository(@IO Scheduler io, @MainThread Scheduler mainThread,
BookDao bookDao,
BookmarksDao bookmarksDao,
HistoryDao historyDao,
NetworkLanguageDao languageDao,
RecentSearchDao recentSearchDao) {
@ -46,6 +50,7 @@ public class Repository implements DataSource {
this.mainThread = mainThread;
this.bookDao = bookDao;
this.languageDao = languageDao;
this.bookmarksDao = bookmarksDao;
this.historyDao = historyDao;
this.recentSearchDao = recentSearchDao;
}
@ -130,4 +135,36 @@ public class Repository implements DataSource {
})
.subscribeOn(io);
}
@Override
public Single<List<Bookmark>> getBookmarks(boolean fromCurrentBook) {
return Single.just(bookmarksDao.getBookmarks(fromCurrentBook))
.subscribeOn(io)
.observeOn(mainThread);
}
@Override
public Single<List<String>> getCurrentZimBookmarksUrl() {
return Single.just(bookmarksDao.getCurrentZimBookmarksUrl())
.subscribeOn(io)
.observeOn(mainThread);
}
@Override
public Completable saveBookmark(Bookmark bookmark) {
return Completable.fromAction(() -> bookmarksDao.saveBookmark(bookmark))
.subscribeOn(io);
}
@Override
public Completable deleteBookmarks(List<Bookmark> bookmarks) {
return Completable.fromAction(() -> bookmarksDao.deleteBookmarks(bookmarks))
.subscribeOn(io);
}
@Override
public Completable deleteBookmark(Bookmark bookmark) {
return Completable.fromAction(() -> bookmarksDao.deleteBookmark(bookmark))
.subscribeOn(io);
}
}

View File

@ -27,19 +27,22 @@ import com.yahoo.squidb.data.adapter.SQLiteDatabaseWrapper;
import com.yahoo.squidb.sql.Table;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.dao.BookDao;
import org.kiwix.kiwixmobile.data.local.dao.BookmarksDao;
import org.kiwix.kiwixmobile.data.local.entity.BookDatabaseEntity;
import org.kiwix.kiwixmobile.data.local.entity.Bookmarks;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.data.local.entity.LibraryDatabaseEntity;
import org.kiwix.kiwixmobile.data.local.entity.NetworkLanguageDatabaseEntity;
import org.kiwix.kiwixmobile.data.local.entity.RecentSearch;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
@ -49,8 +52,8 @@ import static org.kiwix.kiwixmobile.utils.Constants.TAG_KIWIX;
@Singleton
public class KiwixDatabase extends SquidDatabase {
private static final int VERSION = 15;
private Context context;
private static final int VERSION = 16;
private final Context context;
@Inject
public KiwixDatabase(Context context) {
@ -69,7 +72,7 @@ public class KiwixDatabase extends SquidDatabase {
BookDatabaseEntity.TABLE,
LibraryDatabaseEntity.TABLE,
RecentSearch.TABLE,
Bookmarks.TABLE,
Bookmark.TABLE,
NetworkLanguageDatabaseEntity.TABLE,
History.TABLE
};
@ -90,7 +93,7 @@ public class KiwixDatabase extends SquidDatabase {
tryCreateTable(RecentSearch.TABLE);
}
if (newVersion >= 4) {
tryCreateTable(Bookmarks.TABLE);
tryCreateTable(Bookmark.TABLE);
}
if (newVersion >= 5 && oldVersion < 5) {
db.execSQL("DROP TABLE IF EXISTS book");
@ -101,11 +104,11 @@ public class KiwixDatabase extends SquidDatabase {
}
if (newVersion >= 6 && oldVersion < 6) {
db.execSQL("DROP TABLE IF EXISTS Bookmarks");
tryCreateTable(Bookmarks.TABLE);
migrateBookmarks();
tryCreateTable(Bookmark.TABLE);
migrateBookmarksVersion6();
}
if (newVersion >= 6) {
tryCreateTable(Bookmarks.TABLE);
tryCreateTable(Bookmark.TABLE);
}
if (newVersion >= 9) {
db.execSQL("DROP TABLE IF EXISTS book");
@ -126,7 +129,7 @@ public class KiwixDatabase extends SquidDatabase {
}
if (newVersion >= 13) {
tryAddColumn(BookDatabaseEntity.NAME);
tryAddColumn(Bookmarks.ZIM_NAME);
tryAddColumn(Bookmark.ZIM_NAME);
}
if (newVersion >= 14 && oldVersion < 14) {
tryDropTable(BookDatabaseEntity.TABLE);
@ -135,17 +138,38 @@ public class KiwixDatabase extends SquidDatabase {
if (newVersion >= 15 && oldVersion < 15) {
tryCreateTable(History.TABLE);
}
if (newVersion >= 16 && oldVersion < 16) {
tryAddColumn(Bookmark.ZIM_FILE_PATH);
tryAddColumn(Bookmark.FAVICON);
migrateBookmarksVersion16();
}
return true;
}
private void migrateBookmarksVersion16() {
BookmarksDao bookmarksDao = new BookmarksDao(this);
BookDao bookDao = new BookDao(this);
List<Bookmark> bookmarks = bookmarksDao.getBookmarks(false);
List<LibraryNetworkEntity.Book> books = bookDao.getBooks();
for (Bookmark bookmark : bookmarks) {
if (bookmark.getZimId() != null) {
for (LibraryNetworkEntity.Book book : books) {
if (bookmark.getZimId().equals(book.getId())) {
bookmark.setZimFilePath(book.getUrl()).setFavicon(book.getFavicon());
bookmarksDao.saveBookmark(bookmark);
break;
}
}
}
}
}
@Override
protected int getVersion() {
return VERSION;
}
public void migrateBookmarks() {
BookmarksDao bookmarksDao = new BookmarksDao(this);
public void migrateBookmarksVersion6() {
String[] ids = context.fileList();
for (String id : ids) {
if (id.length() == 40 && id.substring(id.length() - 4).equals(".txt")) {
@ -156,10 +180,12 @@ public class KiwixDatabase extends SquidDatabase {
if (stream != null) {
BufferedReader read = new BufferedReader(new InputStreamReader(stream));
while ((in = read.readLine()) != null) {
bookmarksDao.saveBookmark(null, in, idName, idName);
Bookmark bookmark = new Bookmark();
bookmark.setBookmarkUrl("null").setBookmarkTitle(in).setZimId(idName).setZimName(idName);
persist(bookmark);
}
context.deleteFile(id);
Log.d(TAG_KIWIX, "Switched to bookmarkfile " + ZimContentProvider.getId());
Log.d(TAG_KIWIX, "Switched to bookmark file " + ZimContentProvider.getId());
}
} catch (FileNotFoundException e) {
Log.e(TAG_KIWIX, "Bookmark File ( " + id + " ) not found", e);

View File

@ -21,10 +21,12 @@ package org.kiwix.kiwixmobile.data.local.dao;
import com.yahoo.squidb.data.SquidCursor;
import com.yahoo.squidb.sql.Query;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.KiwixDatabase;
import org.kiwix.kiwixmobile.data.local.entity.Bookmarks;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
@ -33,62 +35,76 @@ import javax.inject.Inject;
*/
public class BookmarksDao {
private KiwixDatabase mDb;
private final KiwixDatabase kiwixDatabase;
@Inject
public BookmarksDao(KiwixDatabase kiwixDatabase) {
this.mDb = kiwixDatabase;
}
public ArrayList<String> getBookmarks(String ZimId, String ZimName) {
ArrayList<String> result = new ArrayList<>();
try (SquidCursor<Bookmarks> bookmarkCursor = mDb.query(
Bookmarks.class,
Query.selectDistinct(Bookmarks.BOOKMARK_URL).where(Bookmarks.ZIM_ID.eq(ZimId).or(Bookmarks.ZIM_NAME.eq(ZimName)))
.orderBy(Bookmarks.BOOKMARK_TITLE.asc()))) {
while (bookmarkCursor.moveToNext()) {
result.add(bookmarkCursor.get(Bookmarks.BOOKMARK_URL));
}
}
return result;
}
public ArrayList<String> getBookmarkTitles(String ZimId, String ZimName) {
ArrayList<String> result = new ArrayList<>();
try (SquidCursor<Bookmarks> bookmarkCursor = mDb.query(
Bookmarks.class,
Query.selectDistinct(Bookmarks.BOOKMARK_TITLE).where(Bookmarks.ZIM_ID.eq(ZimId).or(Bookmarks.ZIM_NAME.eq(ZimName)))
.orderBy(Bookmarks.BOOKMARK_TITLE.asc()))) {
while (bookmarkCursor.moveToNext()) {
result.add(bookmarkCursor.get(Bookmarks.BOOKMARK_TITLE));
}
}
return result;
this.kiwixDatabase = kiwixDatabase;
}
/**
* Save bookmark by:
* @param articleUrl Url of the article
* @param articleTitle Title of the article
* @param ZimId Id of zim file containing article
*/
public void saveBookmark(String articleUrl, String articleTitle, String ZimId, String ZimName) {
if (articleUrl != null) {
mDb.persist(new Bookmarks().setBookmarkUrl(articleUrl).setBookmarkTitle(articleTitle).setZimId(ZimId).setZimName(ZimName));
} else {
mDb.persist(new Bookmarks().setBookmarkUrl("null").setBookmarkTitle(articleTitle).setZimId(ZimId).setZimName(ZimName));
* @return Url of the bookmarks from the current Zim file.
*/
public List<String> getCurrentZimBookmarksUrl() {
ArrayList<String> bookmarksUrl = new ArrayList<>();
try (SquidCursor<Bookmark> bookmarkCursor = kiwixDatabase.query(Bookmark.class,
Query.selectDistinct(Bookmark.BOOKMARK_URL)
.where(Bookmark.ZIM_ID.eq(ZimContentProvider.getId())
.or(Bookmark.ZIM_NAME.eq(ZimContentProvider.getName())))
.orderBy(Bookmark.BOOKMARK_TITLE.asc()))) {
while (bookmarkCursor.moveToNext()) {
bookmarksUrl.add(bookmarkCursor.get(Bookmark.BOOKMARK_URL));
}
}
return bookmarksUrl;
}
public void saveBookmark(Bookmark bookmark) {
kiwixDatabase.deleteWhere(Bookmark.class, Bookmark.BOOKMARK_URL.eq(bookmark.getBookmarkUrl())
.and(Bookmark.ZIM_ID.eq(bookmark.getZimId())));
kiwixDatabase.persist(new Bookmark()
.setZimId(bookmark.getZimId())
.setZimName(bookmark.getZimName())
.setZimFilePath(bookmark.getZimFilePath())
.setFavicon(bookmark.getFavicon())
.setBookmarkUrl(bookmark.getBookmarkUrl())
.setBookmarkTitle(bookmark.getBookmarkTitle()));
}
public List<Bookmark> getBookmarks(boolean fromCurrentBook) {
ArrayList<Bookmark> bookmarks = new ArrayList<>();
Query query = Query.select();
if (fromCurrentBook) {
query = query.where(Bookmark.ZIM_ID.eq(ZimContentProvider.getId()));
}
try (SquidCursor<Bookmark> squidCursor = kiwixDatabase
.query(Bookmark.class, query.orderBy(Bookmark.BOOKMARK_TITLE.asc()))) {
while (squidCursor.moveToNext()) {
Bookmark bookmark = new Bookmark();
bookmark.setZimId(squidCursor.get(Bookmark.ZIM_ID));
bookmark.setZimName(squidCursor.get(Bookmark.ZIM_NAME));
bookmark.setZimFilePath(squidCursor.get(Bookmark.ZIM_FILE_PATH));
bookmark.setFavicon(squidCursor.get(Bookmark.FAVICON));
bookmark.setBookmarkTitle(squidCursor.get(Bookmark.BOOKMARK_TITLE));
bookmark.setBookmarkUrl(squidCursor.get(Bookmark.BOOKMARK_URL));
bookmarks.add(bookmark);
}
}
return bookmarks;
}
public void deleteBookmarks(List<Bookmark> bookmarks) {
for (Bookmark bookmark : bookmarks) {
kiwixDatabase.deleteWhere(Bookmark.class, Bookmark.BOOKMARK_URL.eq(bookmark.getBookmarkUrl())
.and(Bookmark.ZIM_ID.eq(bookmark.getZimId())));
}
}
/**
* Delete bookmark satisfying:
* @param favArticle - the article url
* @param ZimId - zim containing article
*/
public void deleteBookmark(String favArticle, String ZimId, String ZimName) {
mDb.deleteWhere(Bookmarks.class, Bookmarks.BOOKMARK_URL.eq(favArticle).and(Bookmarks.ZIM_ID.eq(ZimId).or(Bookmarks.ZIM_NAME.eq(ZimName))) );
public void deleteBookmark(Bookmark bookmark) {
kiwixDatabase.deleteWhere(Bookmark.class, Bookmark.BOOKMARK_URL.eq(bookmark.getBookmarkUrl())
.and(Bookmark.ZIM_ID.eq(bookmark.getZimId())));
}
}

View File

@ -23,13 +23,13 @@ import com.yahoo.squidb.annotations.TableModelSpec;
/**
* Squidb spec for saved bookmarks.
*/
@TableModelSpec(className = "Bookmarks", tableName = "Bookmarks")
@TableModelSpec(className = "Bookmark", tableName = "Bookmarks")
public class BookmarksSpec {
@ColumnSpec(constraints = "NOT NULL")
public String ZimId;
public String ZimName;
public String zimFilePath;
public String bookmarkUrl;
public String bookmarkTitle;
public String favicon;
}

View File

@ -1,6 +1,7 @@
package org.kiwix.kiwixmobile.di.modules;
import org.kiwix.kiwixmobile.bookmark.BookmarksActivity;
import org.kiwix.kiwixmobile.bookmark.BookmarksModule;
import org.kiwix.kiwixmobile.di.PerActivity;
import org.kiwix.kiwixmobile.error.ErrorActivity;
import org.kiwix.kiwixmobile.help.HelpActivity;
@ -45,7 +46,7 @@ public abstract class ActivityBindingModule {
public abstract SearchActivity provideSearchActivity();
@PerActivity
@ContributesAndroidInjector
@ContributesAndroidInjector(modules = BookmarksModule.class)
public abstract BookmarksActivity provideBookmarksActivity();
@PerActivity

View File

@ -39,20 +39,19 @@ public class HistoryActivity extends BaseActivity implements HistoryContract.Vie
private final List<History> fullHistory = new ArrayList<>();
private final List<History> deleteList = new ArrayList<>();
@BindView(R.id.activity_history_toolbar)
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.activity_history_recycler_view)
RecyclerView recyclerView;
@Inject
HistoryContract.Presenter presenter;
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
private boolean refreshAdapter = true;
private HistoryAdapter historyAdapter;
private ActionMode actionMode;
private final ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu_context_history, menu);
mode.getMenuInflater().inflate(R.menu.menu_context_delete, menu);
return true;
}
@ -65,7 +64,7 @@ public class HistoryActivity extends BaseActivity implements HistoryContract.Vie
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
refreshAdapter = false;
switch (item.getItemId()) {
case R.id.menu_context_history_delete:
case R.id.menu_context_delete:
fullHistory.removeAll(deleteList);
for (History history : deleteList) {
int position = historyList.indexOf(history);
@ -107,12 +106,13 @@ public class HistoryActivity extends BaseActivity implements HistoryContract.Vie
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter.attachView(this);
setContentView(R.layout.activity_history);
setContentView(R.layout.activity_bookmarks_history_language);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setTitle(R.string.history);
}
historyAdapter = new HistoryAdapter(historyList, deleteList, this);
recyclerView.setAdapter(historyAdapter);

View File

@ -35,7 +35,7 @@ class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_history, parent, false);
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bookmark_history, parent, false);
return new Item(view);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_date, parent, false);
@ -81,9 +81,9 @@ class HistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
}
class Item extends RecyclerView.ViewHolder {
@BindView(R.id.item_history_favicon)
@BindView(R.id.favicon)
ImageView favicon;
@BindView(R.id.item_history_title)
@BindView(R.id.title)
TextView title;
Item(View itemView) {

View File

@ -27,9 +27,9 @@ public class LanguageActivity extends BaseActivity implements LanguageContract.V
private final ArrayList<Language> languages = new ArrayList<>();
private final ArrayList<Language> allLanguages = new ArrayList<>();
@BindView(R.id.activity_language_toolbar)
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.activity_language_recycler_view)
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
@Inject
LanguageContract.Presenter presenter;
@ -40,7 +40,7 @@ public class LanguageActivity extends BaseActivity implements LanguageContract.V
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
presenter.attachView(this);
setContentView(R.layout.activity_language);
setContentView(R.layout.activity_bookmarks_history_language);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();

View File

@ -83,7 +83,7 @@ import org.kiwix.kiwixmobile.R;
import org.kiwix.kiwixmobile.base.BaseActivity;
import org.kiwix.kiwixmobile.bookmark.BookmarksActivity;
import org.kiwix.kiwixmobile.data.ZimContentProvider;
import org.kiwix.kiwixmobile.data.local.dao.BookmarksDao;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.help.HelpActivity;
import org.kiwix.kiwixmobile.history.HistoryActivity;
@ -118,8 +118,6 @@ import static org.kiwix.kiwixmobile.main.TableDrawerAdapter.DocumentSection;
import static org.kiwix.kiwixmobile.main.TableDrawerAdapter.TableClickListener;
import static org.kiwix.kiwixmobile.search.SearchActivity.EXTRA_SEARCH_IN_TEXT;
import static org.kiwix.kiwixmobile.utils.Constants.BOOKMARK_CHOSEN_REQUEST;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_BOOKMARK_CLICKED;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_BOOKMARK_CONTENTS;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_CHOSE_X_TITLE;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_CHOSE_X_URL;
import static org.kiwix.kiwixmobile.utils.Constants.EXTRA_EXTERNAL_LINK;
@ -158,6 +156,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
public static boolean nightMode;
private static Uri KIWIX_LOCAL_MARKET_URI;
private static Uri KIWIX_BROWSER_MARKET_URI;
private final ArrayList<String> bookmarks = new ArrayList<>();
public List<DocumentSection> documentSections;
public Menu menu;
protected boolean requestClearHistoryAfterLoad = false;
@ -205,14 +204,12 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
@BindView(R.id.bottom_toolbar)
CardView bottomToolbar;
@BindView(R.id.bottom_toolbar_bookmark)
ImageView bookmark;
ImageView bottomToolbarBookmark;
@BindView(R.id.bottom_toolbar_arrow_back)
ImageView bottomToolbarArrowBack;
@BindView(R.id.bottom_toolbar_arrow_forward)
ImageView bottomToolbarArrowForward;
@Inject
BookmarksDao bookmarksDao;
@Inject
MainContract.Presenter presenter;
private boolean isBackToTopEnabled = false;
private boolean wasHideToolbar = true;
@ -223,7 +220,6 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
private String documentParserJs;
private DocumentParser documentParser;
private MenuItem menuBookmarks;
private ArrayList<String> bookmarks;
private List<KiwixWebView> mWebViews = new ArrayList<>();
private KiwixTextToSpeech tts;
private CompatFindActionModeCallback compatCallback;
@ -785,9 +781,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
new Handler().postDelayed(() -> drawerLayout.closeDrawers(), 150);
}
loadPrefs();
if (menu != null) {
refreshBookmarkSymbol(menu);
}
refreshBookmarkSymbol();
updateTableOfContents();
if (!isHideToolbar) {
@ -881,9 +875,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
@OnLongClick(R.id.bottom_toolbar_bookmark)
boolean goToBookmarks() {
saveTabStates();
Intent intentBookmarks = new Intent(getBaseContext(), BookmarksActivity.class);
// FIXME: Looks like EXTRA below isn't used anywhere?
intentBookmarks.putExtra(EXTRA_BOOKMARK_CONTENTS, bookmarks);
Intent intentBookmarks = new Intent(this, BookmarksActivity.class);
startActivityForResult(intentBookmarks, BOOKMARK_CHOSEN_REQUEST);
return true;
}
@ -991,13 +983,8 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
// signal to menu create to show
requestInitAllMenuItems = true;
}
//Bookmarks
bookmarks = new ArrayList<>();
bookmarks = bookmarksDao.getBookmarks(ZimContentProvider.getId(), ZimContentProvider.getName());
openMainPage();
refreshBookmarks();
presenter.loadCurrentZimBookmarksUrl();
return true;
} else {
Toast.makeText(this, getResources().getString(R.string.error_fileinvalid),
@ -1174,17 +1161,29 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
@OnClick(R.id.bottom_toolbar_bookmark)
public void toggleBookmark() {
//Check maybe need refresh
String article = getCurrentWebView().getUrl();
String articleUrl = getCurrentWebView().getUrl();
boolean isBookmark = false;
if (article != null && !bookmarks.contains(article)) {
saveBookmark(article, getCurrentWebView().getTitle());
Bookmark bookmark = new Bookmark();
bookmark.setZimId(ZimContentProvider.getId())
.setZimName(ZimContentProvider.getName())
.setZimFilePath(ZimContentProvider.getZimFile())
.setBookmarkTitle(getCurrentWebView().getTitle())
.setBookmarkUrl(articleUrl)
.setFavicon(ZimContentProvider.getFavicon());
if (articleUrl != null && !bookmarks.contains(articleUrl)) {
if (ZimContentProvider.getId() != null) {
presenter.saveBookmark(bookmark);
} else {
Toast.makeText(this, R.string.unable_to_add_to_bookmarks, Toast.LENGTH_SHORT).show();
}
isBookmark = true;
} else if (article != null) {
deleteBookmark(article);
} else if (articleUrl != null) {
presenter.deleteBookmark(bookmark);
isBookmark = false;
}
popBookmarkSnackbar(isBookmark);
supportInvalidateOptionsMenu();
presenter.loadCurrentZimBookmarksUrl();
}
private void popBookmarkSnackbar(boolean isBookmark) {
@ -1220,9 +1219,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
refresh = false;
recreate();
}
if (menu != null) {
refreshBookmarkSymbol(menu);
}
refreshBookmarkSymbol();
if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) {
if (menu != null) {
menu.getItem(4).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@ -1317,32 +1314,11 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
}
}
private void refreshBookmarks() {
if (bookmarks != null) {
bookmarks.clear();
}
if (bookmarksDao != null) {
bookmarks = bookmarksDao.getBookmarks(ZimContentProvider.getId(), ZimContentProvider.getName());
}
}
// TODO: change saving bookbark by zim name not id
private void saveBookmark(String articleUrl, String articleTitle) {
if (ZimContentProvider.getId() != null) {
bookmarksDao.saveBookmark(articleUrl, articleTitle, ZimContentProvider.getId(), ZimContentProvider.getName());
refreshBookmarks();
} else {
Toast.makeText(this, R.string.unable_to_add_to_bookmarks, Toast.LENGTH_SHORT).show();
}
}
private void deleteBookmark(String article) {
bookmarksDao.deleteBookmark(article, ZimContentProvider.getId(), ZimContentProvider.getName());
refreshBookmarks();
}
public boolean openArticleFromBookmarkTitle(String bookmarkTitle) {
return openArticle(ZimContentProvider.getPageUrlFromTitle(bookmarkTitle));
@Override
public void refreshBookmarksUrl(List<String> urls) {
bookmarks.clear();
bookmarks.addAll(urls);
refreshBookmarkSymbol();
}
private void contentsDrawerHint() {
@ -1446,27 +1422,6 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
Log.i(TAG_KIWIX, "Intent data: " + data);
switch (requestCode) {
case REQUEST_FILE_SELECT:
if (resultCode == RESULT_OK) {
// The URI of the selected file
final Uri uri = data.getData();
File file = null;
if (uri != null) {
String path = uri.getPath();
if (path != null) {
file = new File(path);
}
}
if (file == null) {
Log.i(TAG_KIWIX, "Could not find file");
return;
}
finish();
Intent zimFile = new Intent(MainActivity.this, MainActivity.class);
zimFile.setData(uri);
startActivity(zimFile);
}
break;
case REQUEST_FILE_SEARCH:
if (resultCode == RESULT_OK) {
String title =
@ -1502,33 +1457,11 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
break;
case BOOKMARK_CHOSEN_REQUEST:
if (resultCode == RESULT_OK) {
boolean itemClicked = data.getBooleanExtra(EXTRA_BOOKMARK_CLICKED, false);
if (ZimContentProvider.getId() == null) return;
//Bookmarks
bookmarks = bookmarksDao.getBookmarks(ZimContentProvider.getId(), ZimContentProvider.getName());
if (itemClicked) {
String bookmarkChosen;
if (data.getStringExtra(EXTRA_CHOSE_X_URL) != null) {
bookmarkChosen = data.getStringExtra(EXTRA_CHOSE_X_URL);
newTab();
getCurrentWebView().loadUrl(bookmarkChosen);
} else {
newTab();
bookmarkChosen = data.getStringExtra(EXTRA_CHOSE_X_TITLE);
openArticleFromBookmarkTitle(bookmarkChosen);
}
}
if (menu != null) {
refreshBookmarkSymbol(menu);
}
}
break;
case REQUEST_FILE_SELECT:
case REQUEST_HISTORY_ITEM_CHOSEN:
if (resultCode == RESULT_OK) {
String title = data.getStringExtra(EXTRA_CHOSE_X_TITLE);
String url = data.getStringExtra(EXTRA_CHOSE_X_URL);
if (data.getData() != null) {
final Uri uri = data.getData();
File file = null;
@ -1544,13 +1477,21 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
}
Intent zimFile = new Intent(MainActivity.this, MainActivity.class);
zimFile.setData(uri);
zimFile.putExtra(EXTRA_CHOSE_X_URL, data.getStringExtra(EXTRA_CHOSE_X_URL));
if (url != null) {
zimFile.putExtra(EXTRA_CHOSE_X_URL, url);
} else if (title != null) {
zimFile.putExtra(EXTRA_CHOSE_X_URL, ZimContentProvider.getPageUrlFromTitle(title));
}
startActivity(zimFile);
finish();
return;
}
newTab();
getCurrentWebView().loadUrl(data.getStringExtra(EXTRA_CHOSE_X_URL));
if (url != null) {
getCurrentWebView().loadUrl(url);
} else if (title != null) {
getCurrentWebView().loadUrl(ZimContentProvider.getPageUrlFromTitle(title));
}
}
return;
default:
@ -1604,7 +1545,8 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
toggleActionItemsConfig();
refreshBookmarkSymbol(menu);
this.menu = menu;
refreshBookmarkSymbol();
refreshNavigationButtons();
if (getCurrentWebView().getUrl() == null ||
@ -1617,11 +1559,8 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
return true;
}
public void refreshBookmarkSymbol(Menu menu) { // Checks if current webview is in bookmarks array
if (bookmarks == null || bookmarks.size() == 0) {
bookmarks = bookmarksDao.getBookmarks(ZimContentProvider.getId(), ZimContentProvider.getName());
}
public void refreshBookmarkSymbol() {
if (menu == null) return;
if (menu.findItem(R.id.menu_bookmarks) != null &&
getCurrentWebView().getUrl() != null &&
@ -1634,14 +1573,14 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
.setIcon(icon)
.getIcon().setAlpha(255);
bookmark.setImageResource(icon);
bottomToolbarBookmark.setImageResource(icon);
} else {
menu.findItem(R.id.menu_bookmarks)
.setEnabled(false)
.setIcon(R.drawable.ic_bookmark_border_24dp)
.getIcon().setAlpha(130);
bookmark.setImageResource(R.drawable.ic_bookmark_border_24dp);
bottomToolbarBookmark.setImageResource(R.drawable.ic_bookmark_border_24dp);
}
}
@ -1697,7 +1636,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
}
public void manageZimFiles(int tab) {
refreshBookmarks();
presenter.loadCurrentZimBookmarksUrl();
final Intent target = new Intent(this, ZimManageActivity.class);
target.setAction(Intent.ACTION_GET_CONTENT);
// The MIME data type filter
@ -1859,10 +1798,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
@Override
public void onPause() {
super.onPause();
saveTabStates();
refreshBookmarks();
Log.d(TAG_KIWIX, "onPause Save currentzimfile to preferences: " + ZimContentProvider.getZimFile());
}
@ -1879,10 +1815,7 @@ public class MainActivity extends BaseActivity implements WebViewCallback,
public void webViewUrlFinishedLoading() {
updateTableOfContents();
tabDrawerAdapter.notifyDataSetChanged();
if (menu != null) {
refreshBookmarkSymbol(menu);
}
refreshBookmarkSymbol();
updateBottomToolbarArrowsAlpha();
String url = getCurrentWebView().getUrl();
if (url != null && !url.equals("file:///android_asset/home.html")) {

View File

@ -1,6 +1,7 @@
package org.kiwix.kiwixmobile.main;
import org.kiwix.kiwixmobile.base.BaseContract;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
@ -14,6 +15,8 @@ class MainContract {
interface View extends BaseContract.View<Presenter> {
void addBooks(List<LibraryNetworkEntity.Book> books);
void refreshBookmarksUrl(List<String> urls);
}
interface Presenter extends BaseContract.Presenter<View> {
@ -22,5 +25,11 @@ class MainContract {
void saveBooks(List<LibraryNetworkEntity.Book> books);
void saveHistory(History history);
void loadCurrentZimBookmarksUrl();
void saveBookmark(Bookmark bookmark);
void deleteBookmark(Bookmark bookmark);
}
}

View File

@ -7,13 +7,6 @@ import dagger.Provides;
@Module
public class MainModule {
@PerActivity
@Provides
MainContract.View provideMainView(MainActivity mainActivity) {
return mainActivity;
}
@PerActivity
@Provides
MainContract.Presenter provideMainPresenter(MainPresenter mainPresenter) {

View File

@ -4,6 +4,7 @@ import android.util.Log;
import org.kiwix.kiwixmobile.base.BasePresenter;
import org.kiwix.kiwixmobile.data.DataSource;
import org.kiwix.kiwixmobile.data.local.entity.Bookmark;
import org.kiwix.kiwixmobile.data.local.entity.History;
import org.kiwix.kiwixmobile.di.PerActivity;
import org.kiwix.kiwixmobile.library.entity.LibraryNetworkEntity;
@ -23,7 +24,7 @@ import io.reactivex.disposables.Disposable;
@PerActivity
class MainPresenter extends BasePresenter<MainContract.View> implements MainContract.Presenter {
private DataSource dataSource;
private final DataSource dataSource;
@Inject
MainPresenter(DataSource dataSource) {
@ -77,4 +78,52 @@ class MainPresenter extends BasePresenter<MainContract.View> implements MainCont
}
});
}
@Override
public void loadCurrentZimBookmarksUrl() {
compositeDisposable.add(dataSource.getCurrentZimBookmarksUrl()
.subscribe(view::refreshBookmarksUrl, e -> Log.e("MainPresenter", e.toString())));
}
@Override
public void saveBookmark(Bookmark bookmark) {
dataSource.saveBookmark(bookmark)
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
Log.e("MainPresenter", e.toString());
}
});
}
@Override
public void deleteBookmark(Bookmark bookmark) {
dataSource.deleteBookmark(bookmark)
.subscribe(new CompletableObserver() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onComplete() {
}
@Override
public void onError(Throwable e) {
Log.e("MainPresenter", e.toString());
}
});
}
}

View File

@ -108,8 +108,6 @@ public final class Constants {
public static final String EXTRA_SEARCH = "search";
public static final String EXTRA_BOOKMARK_CLICKED = "bookmarkClicked";
public static final String EXTRA_BOOK = "Book";
public static final String EXTRA_IS_WIDGET_VOICE = "isWidgetVoice";
@ -122,8 +120,6 @@ public final class Constants {
public static final String EXTRA_WEBVIEWS_LIST = "webviewsList";
public static final String EXTRA_BOOKMARK_CONTENTS = "bookmark_contents";
public static final String EXTRA_SEARCH_TEXT = "searchText";
// Notification Channel Constants

View File

@ -33,6 +33,7 @@ import static org.kiwix.kiwixmobile.utils.Constants.PREF_ZOOM_ENABLED;
@Singleton
public class SharedPreferenceUtil {
private static final String PREF_SHOW_BOOKMARKS_CURRENT_BOOK = "show_bookmarks_current_book";
private static final String PREF_SHOW_HISTORY_CURRENT_BOOK = "show_history_current_book";
private SharedPreferences sharedPreferences;
@ -160,4 +161,12 @@ public class SharedPreferenceUtil {
return getPrefNightMode();
}
}
public boolean getShowBookmarksCurrentBook() {
return sharedPreferences.getBoolean(PREF_SHOW_BOOKMARKS_CURRENT_BOOK, true);
}
public void setShowBookmarksCurrentBook(boolean prefShowBookmarksFromCurrentBook) {
sharedPreferences.edit().putBoolean(PREF_SHOW_BOOKMARKS_CURRENT_BOOK, prefShowBookmarksFromCurrentBook).apply();
}
}

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:color="@color/black_regular_mat_design"/>
<item
android:state_activated="true"
android:color="@color/greyed_out_selected"/>
<item
android:color="@color/black_regular_mat_design" />
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -1,76 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bookmarks_activity_layout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fitsSystemWindows="true"
tools:context=".bookmark.BookmarksActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="?actionBarSize">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
android:background="?colorPrimaryDark"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:theme="@style/AppTheme.AppBarOverlay" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/bookmarks_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/listBackground" />
<LinearLayout
android:id="@+id/bookmarks_none_linlayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone">
<ImageView
android:layout_width="@dimen/activity_bookmarks_img_width"
android:layout_height="@dimen/activity_bookmarks_img_height"
android:src="@drawable/ic_star_yellow" />
<TextView
style="@android:style/TextAppearance.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:paddingBottom="@dimen/activity_bookmarks_vertical_padding"
android:paddingLeft="@dimen/activity_bookmarks_horizontal_padding"
android:paddingRight="@dimen/activity_bookmarks_horizontal_padding"
android:paddingTop="@dimen/activity_bookmarks_vertical_padding"
android:text="@string/no_bookmarks"
android:visibility="visible" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>

View File

@ -1,35 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/listBackground"
android:fitsSystemWindows="true"
tools:context=".language.LanguageActivity">
android:fitsSystemWindows="true">
<android.support.design.widget.AppBarLayout
android:id="@+id/activity_language_appbar"
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent">
<android.support.v7.widget.Toolbar
android:id="@+id/activity_language_toolbar"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/activity_language_recycler_view"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_language_appbar" />
app:layout_constraintTop_toBottomOf="@id/appbar" />
</android.support.constraint.ConstraintLayout>

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/listBackground"
android:fitsSystemWindows="true"
tools:context=".history.HistoryActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/activity_history_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/activity_history_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/AppTheme.AppBarOverlay"
app:layout_constraintTop_toTopOf="parent"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="@string/history" />
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/activity_history_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layoutManager="android.support.v7.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/activity_history_appbar" />
</android.support.constraint.ConstraintLayout>

View File

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground">
<TextView
android:id="@+id/bookmark_title"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_margin="@dimen/bookmark_title_margin"
android:textColor="@drawable/bookmarks_selector"
android:textSize="@dimen/bookmark_title_text_size" />
</LinearLayout>
</LinearLayout>

View File

@ -6,7 +6,7 @@
android:layout_height="64dp">
<ImageView
android:id="@+id/item_history_favicon"
android:id="@+id/favicon"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
@ -18,7 +18,7 @@
tools:src="@mipmap/kiwix_icon_round" />
<TextView
android:id="@+id/item_history_title"
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/activity_horizontal_margin"
@ -26,7 +26,7 @@
android:alpha="0.87"
android:textAppearance="?android:attr/textAppearanceMedium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/item_history_favicon"
app:layout_constraintStart_toEndOf="@id/favicon"
app:layout_constraintTop_toTopOf="parent"
tools:text="Wikipedia - Main Page" />
</android.support.constraint.ConstraintLayout>

View File

@ -3,10 +3,16 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_bookmarks_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/delete"
android:titleCondensed="Delete"
app:showAsAction="always" />
android:id="@+id/menu_bookmarks_search"
android:icon="@drawable/action_search"
android:title="@string/search_label"
app:actionViewClass="android.support.v7.widget.SearchView"
app:iconifiedByDefault="true"
app:showAsAction="ifRoom|collapseActionView" />
<item
android:id="@+id/menu_bookmarks_toggle"
android:checkable="true"
android:title="@string/bookmarks_from_current_book"
app:showAsAction="never" />
</menu>

View File

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_context_history_delete"
android:id="@+id/menu_context_delete"
android:icon="@drawable/ic_delete_white_24dp"
android:title="@string/delete"
app:showAsAction="ifRoom" />

View File

@ -234,4 +234,6 @@
<item>@string/help_18</item>
<item>@string/help_19</item>
</string-array>
<string name="bookmarks_from_current_book">Bookmarks from current book</string>
<string name="search_bookmarks">Search bookmarks</string>
</resources>