From 572449f6c66adfc1a3d88e761cb87581a7961df3 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Fri, 18 Jan 2019 16:11:06 -0700 Subject: [PATCH] Add a context menu to delete bookmarks from the database view activity. https://redmine.stoutner.com/issues/220 --- .../activities/BookmarksActivity.java | 177 ++++----- .../BookmarksDatabaseViewActivity.java | 340 +++++++++++++++++- .../activities/MainWebViewActivity.java | 24 +- .../dialogs/CreateBookmarkFolderDialog.java | 4 +- .../EditBookmarkDatabaseViewDialog.java | 6 +- .../dialogs/EditBookmarkDialog.java | 4 +- .../EditBookmarkFolderDatabaseViewDialog.java | 10 +- .../dialogs/EditBookmarkFolderDialog.java | 8 +- .../dialogs/MoveToFolderDialog.java | 14 +- .../helpers/BookmarksDatabaseHelper.java | 207 ++++++++--- .../helpers/ImportExportDatabaseHelper.java | 4 +- ...okmarks_databaseview_coordinatorlayout.xml | 6 +- ...okmarks_databaseview_item_linearlayout.xml | 5 +- .../bookmarks_databaseview_context_menu.xml | 39 ++ app/src/main/res/values-ru/strings.xml | 3 + app/src/main/res/values-tr/strings.xml | 129 ++++++- app/src/main/res/values/strings.xml | 3 +- 17 files changed, 762 insertions(+), 221 deletions(-) create mode 100644 app/src/main/res/menu/bookmarks_databaseview_context_menu.xml diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java index e6c993ab..576e6532 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -65,7 +65,7 @@ import java.io.ByteArrayOutputStream; public class BookmarksActivity extends AppCompatActivity implements CreateBookmarkDialog.CreateBookmarkListener, CreateBookmarkFolderDialog.CreateBookmarkFolderListener, EditBookmarkDialog.EditBookmarkListener, EditBookmarkFolderDialog.EditBookmarkFolderListener, MoveToFolderDialog.MoveToFolderListener { - // `currentFolder` is public static so it can be accessed from `MoveToFolderDialog`. + // `currentFolder` is public static so it can be accessed from `MoveToFolderDialog` and `BookmarksDatabaseViewActivity`. // It is used in `onCreate`, `onOptionsItemSelected()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`, `onMoveToFolder()`, // and `loadFolder()`. public static String currentFolder; @@ -74,6 +74,9 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // and `updateMoveIcons()`. public static long[] checkedItemIds; + // `restartFromBookmarksDatabaseViewActivity` is public static so it can be accessed from `BookmarksDatabaseViewActivity`. It is also used in `onRestart()`. + public static boolean restartFromBookmarksDatabaseViewActivity; + // `bookmarksDatabaseHelper` is used in `onCreate()`, `onOptionsItemSelected()`, `onBackPressed()`, `onCreateBookmark()`, `onCreateBookmarkFolder()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`, // `onMoveToFolder()`, `deleteBookmarkFolderContents()`, `loadFolder()`, and `onDestroy()`. @@ -169,7 +172,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma int databaseID = (int) id; // Get the bookmark cursor for this ID and move it to the first row. - Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmarkCursor(databaseID); + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseID); bookmarkCursor.moveToFirst(); // Act upon the bookmark according to the type. @@ -203,7 +206,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Get a handle for the activity. Activity activity = this; - // `MultiChoiceModeListener` handles long clicks. + // Handle long presses on the list view. bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { // Instantiate the common variables. MenuItem editBookmarkMenuItem; @@ -213,18 +216,17 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { - // Inflate the menu for the contextual app bar and set the title. + // Inflate the menu for the contextual app bar. getMenuInflater().inflate(R.menu.bookmarks_context_menu, menu); // Set the title. - if (currentFolder.isEmpty()) { - // Use `R.string.bookmarks` if we are in the home folder. + if (currentFolder.isEmpty()) { // Use `R.string.bookmarks` if in the home folder. mode.setTitle(R.string.bookmarks); } else { // Use the current folder name as the title. mode.setTitle(currentFolder); } - // Get a handle for `MenuItems` that need to be selectively disabled. + // Get handles for menu items that need to be selectively disabled. moveBookmarkUpMenuItem = menu.findItem(R.id.move_bookmark_up); moveBookmarkDownMenuItem = menu.findItem(R.id.move_bookmark_down); editBookmarkMenuItem = menu.findItem(R.id.edit_bookmark); @@ -232,11 +234,9 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma selectAllBookmarksMenuItem = menu.findItem(R.id.context_menu_select_all_bookmarks); // Disable the delete bookmarks menu item if a delete is pending. - if (deletingBookmarks) { - deleteBookmarksMenuItem.setEnabled(false); - } + deleteBookmarksMenuItem.setEnabled(!deletingBookmarks); - // Store `contextualActionMode` so it can be closed programatically. + // Store a handle for the contextual action mode so it can be closed programatically. contextualActionMode = mode; // Make it so. @@ -248,8 +248,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Get a handle for the move to folder menu item. MenuItem moveToFolderMenuItem = menu.findItem(R.id.move_to_folder); - // Get a `Cursor` with all of the folders. - Cursor folderCursor = bookmarksDatabaseHelper.getAllFoldersCursor(); + // Get a Cursor with all of the folders. + Cursor folderCursor = bookmarksDatabaseHelper.getAllFolders(); // Enable the move to folder menu item if at least one folder exists. moveToFolderMenuItem.setVisible(folderCursor.getCount() > 0); @@ -260,17 +260,11 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @Override public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { - // Get a long array of the selected bookmarks. - long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds(); - - // Calculate the number of selected bookmarks. - int numberOfSelectedBookmarks = selectedBookmarksLongArray.length; + // Get the number of selected bookmarks. + int numberOfSelectedBookmarks = bookmarksListView.getCheckedItemCount(); - // Adjust the `ActionMode` and the `Menu` according to the number of selected bookmarks. - if (numberOfSelectedBookmarks == 0) { // No bookmarks are selected. - // Close the `ActionMode`. - mode.finish(); - } else if (numberOfSelectedBookmarks == 1) { // One bookmark is selected. + // Adjust the ActionMode and the menu according to the number of selected bookmarks. + if (numberOfSelectedBookmarks == 1) { // One bookmark is selected. // List the number of selected bookmarks in the subtitle. mode.setSubtitle(getString(R.string.selected) + " 1"); @@ -291,8 +285,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma editBookmarkMenuItem.setVisible(false); } - // Do not show `Select All` if all the bookmarks are already checked. - if (bookmarksListView.getCheckedItemIds().length == bookmarksListView.getCount()) { + // Do not show the select all menu item if all the bookmarks are already checked. + if (bookmarksListView.getCheckedItemCount() == bookmarksListView.getCount()) { selectAllBookmarksMenuItem.setVisible(false); } else { selectAllBookmarksMenuItem.setVisible(true); @@ -301,15 +295,12 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // Get the menu item ID. - int menuItemId = item.getItemId(); - // Instantiate the common variables. int selectedBookmarkPosition; int selectedBookmarkNewPosition; final SparseBooleanArray selectedBookmarksPositionsSparseBooleanArray; - switch (menuItemId) { + switch (item.getItemId()) { case R.id.move_bookmark_up: // Get the array of checked bookmark positions. selectedBookmarksPositionsSparseBooleanArray = bookmarksListView.getCheckedItemPositions(); @@ -343,8 +334,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } } - // Update `bookmarksCursor` with the current contents of the bookmarks database. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of the bookmarks database. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -389,8 +380,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } } - // Update `bookmarksCursor` with the current contents of the bookmarks database. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of the bookmarks database. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -447,18 +438,19 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Get an array of the selected row IDs. final long[] selectedBookmarksIdsLongArray = bookmarksListView.getCheckedItemIds(); - // Get the array of checked bookmarks. `.clone()` makes a copy that won't change if `bookmarksListView` is reloaded, which is needed for re-selecting the bookmarks on undelete. + // Get an array of checked bookmarks. `.clone()` makes a copy that won't change if the list view is reloaded, which is needed for re-selecting the bookmarks on undelete. selectedBookmarksPositionsSparseBooleanArray = bookmarksListView.getCheckedItemPositions().clone(); - // Update `bookmarksCursor` with the current contents of the bookmarks database except for the specified database IDs. - bookmarksCursor = bookmarksDatabaseHelper.getBookmarksCursorExcept(selectedBookmarksIdsLongArray, currentFolder); + // Update the bookmarks cursor with the current contents of the bookmarks database except for the specified database IDs. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrderExcept(selectedBookmarksIdsLongArray, currentFolder); - // Update the `ListView`. + // Update the list view. bookmarksCursorAdapter.changeCursor(bookmarksCursor); // Show a Snackbar with the number of deleted bookmarks. bookmarksDeletedSnackbar = Snackbar.make(findViewById(R.id.bookmarks_coordinatorlayout), getString(R.string.bookmarks_deleted) + " " + selectedBookmarksIdsLongArray.length, - Snackbar.LENGTH_LONG).setAction(R.string.undo, view -> { + Snackbar.LENGTH_LONG) + .setAction(R.string.undo, view -> { // Do nothing because everything will be handled by `onDismissed()` below. }) .addCallback(new Snackbar.Callback() { @@ -467,20 +459,19 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma switch (event) { // The user pushed the `Undo` button. case Snackbar.Callback.DISMISS_EVENT_ACTION: - // Update `bookmarksCursor` with the current contents of the bookmarks database, including the "deleted" bookmarks. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of the bookmarks database, including the "deleted" bookmarks. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); - // Update the `ListView`. + // Update the list view. bookmarksCursorAdapter.changeCursor(bookmarksCursor); // Re-select the previously selected bookmarks. for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) { bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true); } - break; - // The `Snackbar` was dismissed without the `Undo` button being pushed. + // The Snackbar was dismissed without the `Undo` button being pushed. default: // Delete each selected bookmark. for (long databaseIdLong : selectedBookmarksIdsLongArray) { @@ -511,31 +502,21 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } } - // Enable the delete bookmarks menu item. - deleteBookmarksMenuItem.setEnabled(true); - // Reset the deleting bookmarks flag. deletingBookmarks = false; + // Enable the delete bookmarks menu item. + deleteBookmarksMenuItem.setEnabled(true); + // Close the activity if back has been pressed. if (closeActivityAfterDismissingSnackbar) { - // Update the bookmarks folder for the bookmarks drawer in the main WebView activity. - MainWebViewActivity.currentBookmarksFolder = currentFolder; - - // Close the bookmarks drawer and reload the bookmarks ListView when returning to the main WebView activity. - MainWebViewActivity.restartFromBookmarksActivity = true; - - // Return to `MainWebViewActivity`. - NavUtils.navigateUpFromSameTask(activity); + onBackPressed(); } } }); - //Show the `SnackBar`. + //Show the Snackbar. bookmarksDeletedSnackbar.show(); - - // Close the `ActionBar`. - mode.finish(); break; case R.id.context_menu_select_all_bookmarks: @@ -578,6 +559,21 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma }); } + @Override + public void onRestart() { + // Run the default commands. + super.onRestart(); + + // Update the list view if returning from the bookmarks database view activity. + if (restartFromBookmarksDatabaseViewActivity) { + // Load the current folder in the list view. + loadFolder(); + + // Reset `restartFromBookmarksDatabaseViewActivity`. + restartFromBookmarksDatabaseViewActivity = false; + } + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu. @@ -589,32 +585,14 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @Override public boolean onOptionsItemSelected(MenuItem menuItem) { - // Get the ID of the menu item that was selected. - int menuItemId = menuItem.getItemId(); - - switch (menuItemId) { + switch (menuItem.getItemId()) { case android.R.id.home: // The home arrow is identified as `android.R.id.home`, not just `R.id.home`. if (currentFolder.isEmpty()) { // Currently in the home folder. - // Go home. - if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks delete snackbar before going home. - // Set the close flag. - closeActivityAfterDismissingSnackbar = true; - - // Dismiss the snackbar. - bookmarksDeletedSnackbar.dismiss(); - } else { // Go home immediately. - // Update the bookmarks folder for the bookmarks drawer in `MainWebViewActivity`. - MainWebViewActivity.currentBookmarksFolder = ""; - - // Close the bookmarks drawer and reload the bookmarks `ListView` when returning to `MainWebViewActivity`. - MainWebViewActivity.restartFromBookmarksActivity = true; - - // Return to `MainWebViewActivity`. - NavUtils.navigateUpFromSameTask(this); - } + // Run the back commands. + onBackPressed(); } else { // Currently in a subfolder. // Place the former parent folder in `currentFolder`. - currentFolder = bookmarksDatabaseHelper.getParentFolder(currentFolder); + currentFolder = bookmarksDatabaseHelper.getParentFolderName(currentFolder); // Load the new folder. loadFolder(); @@ -642,8 +620,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma @Override public void onBackPressed() { - // Check to see if a snackbar is currently displayed. If so, it must be closed before exiting so that a pending delete is completed before reloading the ListView in the bookmarks drawer. - if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks delete snackbar before going home. + // Check to see if a snackbar is currently displayed. If so, it must be closed before exiting so that a pending delete is completed before reloading the list view in the bookmarks drawer. + if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks deleted snackbar before going home. // Set the close flag. closeActivityAfterDismissingSnackbar = true; @@ -656,7 +634,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Close the bookmarks drawer and reload the bookmarks ListView when returning to the main WebView activity. MainWebViewActivity.restartFromBookmarksActivity = true; - // Exit `BookmarksActivity`. + // Exit the bookmarks activity. super.onBackPressed(); } } @@ -682,8 +660,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Create the bookmark. bookmarksDatabaseHelper.createBookmark(bookmarkNameString, bookmarkUrlString, currentFolder, newBookmarkDisplayOrder, favoriteIconByteArray); - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -727,8 +705,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Create the folder, which will be placed at the top of the `ListView`. bookmarksDatabaseHelper.createFolder(folderNameString, currentFolder, folderIconByteArray); - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -764,8 +742,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Close the contextual action mode. contextualActionMode.finish(); - // Update `bookmarksCursor` with the contents of the current folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the contents of the current folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -828,8 +806,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma bookmarksDatabaseHelper.updateFolder(selectedFolderDatabaseId, oldFolderNameString, newFolderNameString, folderIconByteArray); } - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -873,8 +851,8 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma bookmarksDatabaseHelper.moveToFolder(databaseIdInt, newFolderName); } - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -888,7 +866,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma String folderName = bookmarksDatabaseHelper.getFolderName(databaseId); // Get the contents of the folder. - Cursor folderCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(folderName); + Cursor folderCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(folderName); // Delete each of the bookmarks in the folder. for (int i = 0; i < folderCursor.getCount(); i++) { @@ -969,15 +947,16 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma if (selectedBookmarkPosition <= firstVisibleBookmarkPosition) { // The selected bookmark position is at or above the top of the screen. // Scroll to the selected bookmark position. bookmarksListView.setSelection(selectedBookmarkPosition); - } else if (selectedBookmarkPosition >= (lastVisibleBookmarkPosition - 1)) { // The selected bookmark is at or below the bottom of the screen. The `-1` handles partial bookmarks displayed at the bottom of the `ListView`. - // Scroll to display the selected bookmark at the bottom of the screen. `+1` assured that the entire bookmark will be displayed in situations where only a partial bookmark fits at the bottom of the `ListView`. + } else if (selectedBookmarkPosition >= (lastVisibleBookmarkPosition - 1)) { // The selected bookmark is at or below the bottom of the screen. + // The `-1` handles partial bookmarks displayed at the bottom of the list view. This command scrolls to display the selected bookmark at the bottom of the screen. + // `+1` assures that the entire bookmark will be displayed in situations where only a partial bookmark fits at the bottom of the list view. bookmarksListView.setSelection(selectedBookmarkPosition - numberOfBookmarksPerScreen + 1); } } private void loadFolder() { - // Update `bookmarksCursor` with the contents of the bookmarks database for the current folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolder); + // Update bookmarks cursor with the contents of the bookmarks database for the current folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolder); // Setup a `CursorAdapter`. `this` specifies the `Context`. `false` disables `autoRequery`. bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) { @@ -1015,7 +994,7 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma } }; - // Populate the `ListView` with the adapter. + // Populate the list view with the adapter. bookmarksListView.setAdapter(bookmarksCursorAdapter); // Set the `AppBar` title. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java index 1f011f72..dd9c42cf 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java @@ -30,7 +30,6 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.design.widget.Snackbar; -import android.support.v4.app.NavUtils; import android.support.v4.content.ContextCompat; import android.support.v4.widget.CursorAdapter; import android.support.v4.widget.ResourceCursorAdapter; @@ -39,11 +38,14 @@ import android.support.v7.app.AppCompatActivity; // `AppCompatDialogFragment` is required instead of `DialogFragment` or an error is produced on API <=22. import android.support.v7.app.AppCompatDialogFragment; import android.support.v7.widget.Toolbar; +import android.util.SparseBooleanArray; +import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; +import android.widget.AbsListView; import android.widget.AdapterView; import android.widget.EditText; import android.widget.ImageView; @@ -59,18 +61,19 @@ import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; import java.io.ByteArrayOutputStream; -public class BookmarksDatabaseViewActivity extends AppCompatActivity implements EditBookmarkDatabaseViewDialog.EditBookmarkDatabaseViewListener, EditBookmarkFolderDatabaseViewDialog.EditBookmarkFolderDatabaseViewListener { +public class BookmarksDatabaseViewActivity extends AppCompatActivity implements EditBookmarkDatabaseViewDialog.EditBookmarkDatabaseViewListener, + EditBookmarkFolderDatabaseViewDialog.EditBookmarkFolderDatabaseViewListener { // Instantiate the constants. private static final int ALL_FOLDERS_DATABASE_ID = -2; private static final int HOME_FOLDER_DATABASE_ID = -1; - // `bookmarksDatabaseHelper` is used in `onCreate()`, `updateBookmarksListView()`, and `onDestroy()`. + // `bookmarksDatabaseHelper` is used in `onCreate()`, `updateBookmarksListView()`, `selectAllBookmarksInFolder()`, and `onDestroy()`. private BookmarksDatabaseHelper bookmarksDatabaseHelper; // `bookmarksCursor` is used in `onCreate()`, `updateBookmarksListView()`, `onSaveBookmark()`, `onSaveBookmarkFolder()`, and `onDestroy()`. private Cursor bookmarksCursor; - // `bookmarksCursorAdapter` is used in `onCreate()` and `updateBookmarksListView()`. + // `bookmarksCursorAdapter` is used in `onCreate()`, `selectAllBookmarksInFolder()`, and `updateBookmarksListView()`. private CursorAdapter bookmarksCursorAdapter; // `oldFolderNameString` is used in `onCreate()` and `onSaveBookmarkFolder()`. @@ -85,6 +88,12 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // `sortByDisplayOrder` is used in `onCreate()`, `onOptionsItemSelected()`, and `updateBookmarksListView()`. private boolean sortByDisplayOrder; + // `bookmarksDeletedSnackbar` is used in `onCreate()`, `onOptionsItemSelected()`, and `onBackPressed()`. + private Snackbar bookmarksDeletedSnackbar; + + // `closeActivityAfterDismissingSnackbar` is used in `onCreate()`, `onOptionsItemSelected()`, and `onBackPressed()`. + private boolean closeActivityAfterDismissingSnackbar; + @Override public void onCreate(Bundle savedInstanceState) { // Disable screenshots if not allowed. @@ -119,7 +128,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements appBar.setCustomView(R.layout.spinner); appBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_HOME_AS_UP); - // Initialize the database handler. `this` specifies the context. The two `null`s do not specify the database name or a `CursorFactory`. The `0` is to specify a database version, but that is set instead using a constant in `BookmarksDatabaseHelper`. + // Initialize the database handler. `this` specifies the context. The `0` is to specify a database version, but that is set instead using a constant in `BookmarksDatabaseHelper`. bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this, null, null, 0); // Setup a matrix cursor for "All Folders" and "Home Folder". @@ -128,8 +137,8 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements matrixCursor.addRow(new Object[]{ALL_FOLDERS_DATABASE_ID, getString(R.string.all_folders)}); matrixCursor.addRow(new Object[]{HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)}); - // Get a `Cursor` with the list of all the folders. - Cursor foldersCursor = bookmarksDatabaseHelper.getAllFoldersCursor(); + // Get a cursor with the list of all the folders. + Cursor foldersCursor = bookmarksDatabaseHelper.getAllFolders(); // Combine `matrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); @@ -153,7 +162,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements Spinner folderSpinner = findViewById(R.id.spinner); folderSpinner.setAdapter(foldersCursorAdapter); - // Handle clicks on the spinner dropdown. + // Handle taps on the spinner dropdown. folderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { @@ -180,7 +189,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements ListView bookmarksListView = findViewById(R.id.bookmarks_databaseview_listview); // Get a `Cursor` with the current contents of the bookmarks database. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(); + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarks(); // Setup a `CursorAdapter` with `this` context. `false` disables autoRequery. bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) { @@ -269,7 +278,7 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Set a listener to edit a bookmark when it is tapped. bookmarksListView.setOnItemClickListener((AdapterView parent, View view, int position, long id) -> { - // Convert the database ID to an `int`. + // Convert the database ID to an int. int databaseId = (int) id; // Show the edit bookmark or edit bookmark folder dialog. @@ -286,6 +295,218 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements editBookmarkDatabaseViewDialog.show(getSupportFragmentManager(), getResources().getString(R.string.edit_bookmark)); } }); + + // Handle long presses on the list view. + bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { + // Instantiate the common variables. + MenuItem selectAllMenuItem; + MenuItem deleteMenuItem; + boolean deletingBookmarks; + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate the menu for the contextual app bar. + getMenuInflater().inflate(R.menu.bookmarks_databaseview_context_menu, menu); + + // Set the title. + mode.setTitle(R.string.bookmarks); + + // Get handles for the menu items. + selectAllMenuItem = menu.findItem(R.id.select_all); + deleteMenuItem = menu.findItem(R.id.delete); + + // Disable the delete menu item if a delete is pending. + deleteMenuItem.setEnabled(!deletingBookmarks); + + // Make it so. + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + // Do nothing. + return false; + } + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { + // Calculate the number of selected bookmarks. + int numberOfSelectedBookmarks = bookmarksListView.getCheckedItemCount(); + + // Adjust the ActionMode according to the number of selected bookmarks. + mode.setSubtitle(getString(R.string.selected) + " " + numberOfSelectedBookmarks); + + // Do not show the select all menu item if all the bookmarks are already checked. + if (bookmarksListView.getCheckedItemCount() == bookmarksListView.getCount()) { + selectAllMenuItem.setVisible(false); + } else { + selectAllMenuItem.setVisible(true); + } + + // Convert the database ID to an int. + int databaseId = (int) id; + + // If a folder was selected, also select all the contents. + if (checked && bookmarksDatabaseHelper.isFolder(databaseId)) { + selectAllBookmarksInFolder(databaseId); + } + + // Do not allow a bookmark to be deselected if the folder is selected. + if (!checked) { + // Get the folder name. + String folderName = bookmarksDatabaseHelper.getParentFolderName((int) id); + + // If the bookmark is not in the root folder, check to see if the folder is selected. + if (!folderName.isEmpty()) { + // Get the database ID of the folder. + int folderDatabaseId = bookmarksDatabaseHelper.getFolderDatabaseId(folderName); + + // Move the bookmarks cursor to the first position. + bookmarksCursor.moveToFirst(); + + // Initialize the folder position variable. + int folderPosition = -1; + + // Get the position of the folder in the bookmarks cursor. + while ((folderPosition < 0) && (bookmarksCursor.getPosition() < bookmarksCursor.getCount())) { + // Check if the folder database ID matches the bookmark database ID. + if (folderDatabaseId == bookmarksCursor.getInt((bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper._ID)))) { + // Get the folder position. + folderPosition = bookmarksCursor.getPosition(); + + // Check if the folder is selected. + if (bookmarksListView.isItemChecked(folderPosition)) { + // Reselect the bookmark. + bookmarksListView.setItemChecked(position, true); + + // Display a snackbar explaining why the bookmark cannot be deselected. + Snackbar.make(bookmarksListView, R.string.cannot_deselect_bookmark, Snackbar.LENGTH_LONG).show(); + } + } + + // Increment the bookmarks cursor. + bookmarksCursor.moveToNext(); + } + } + } + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + switch (item.getItemId()) { + case R.id.select_all: + // Get the total number of bookmarks. + int numberOfBookmarks = bookmarksListView.getCount(); + + // Select them all. + for (int i = 0; i < numberOfBookmarks; i++) { + bookmarksListView.setItemChecked(i, true); + } + break; + + case R.id.delete: + // Set the deleting bookmarks flag, which prevents the delete menu item from being enabled until the current process finishes. + deletingBookmarks = true; + + // Get an array of the selected row IDs. + long[] selectedBookmarksIdsLongArray = bookmarksListView.getCheckedItemIds(); + + // Get an array of checked bookmarks. `.clone()` makes a copy that won't change if the list view is reloaded, which is needed for re-selecting the bookmarks on undelete. + SparseBooleanArray selectedBookmarksPositionsSparseBooleanArray = bookmarksListView.getCheckedItemPositions().clone(); + + // Update the bookmarks cursor with the current contents of the bookmarks database except for the specified database IDs. + switch (currentFolderDatabaseId) { + // Get a cursor with all the folders. + case ALL_FOLDERS_DATABASE_ID: + if (sortByDisplayOrder) { + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksByDisplayOrderExcept(selectedBookmarksIdsLongArray); + } else { + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksExcept(selectedBookmarksIdsLongArray); + } + break; + + // Get a cursor for the home folder. + case HOME_FOLDER_DATABASE_ID: + if (sortByDisplayOrder) { + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrderExcept(selectedBookmarksIdsLongArray, ""); + } else { + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksExcept(selectedBookmarksIdsLongArray, ""); + } + break; + + // Display the selected folder. + default: + // Get a cursor for the selected folder. + if (sortByDisplayOrder) { + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrderExcept(selectedBookmarksIdsLongArray, currentFolderName); + } else { + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksExcept(selectedBookmarksIdsLongArray, currentFolderName); + } + } + + // Update the list view. + bookmarksCursorAdapter.changeCursor(bookmarksCursor); + + // Show a Snackbar with the number of deleted bookmarks. + bookmarksDeletedSnackbar = Snackbar.make(findViewById(R.id.bookmarks_databaseview_coordinatorlayout), + getString(R.string.bookmarks_deleted) + " " + selectedBookmarksIdsLongArray.length, Snackbar.LENGTH_LONG) + .setAction(R.string.undo, view -> { + // Do nothing because everything will be handled by `onDismissed()` below. + }) + .addCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + switch (event) { + // The user pushed the `Undo` button. + case Snackbar.Callback.DISMISS_EVENT_ACTION: + // Update the bookmarks list view with the current contents of the bookmarks database, including the "deleted bookmarks. + updateBookmarksListView(); + + // Re-select the previously selected bookmarks. + for (int i = 0; i < selectedBookmarksPositionsSparseBooleanArray.size(); i++) { + bookmarksListView.setItemChecked(selectedBookmarksPositionsSparseBooleanArray.keyAt(i), true); + } + break; + + // The Snackbar was dismissed without the `Undo` button being pushed. + default: + // Delete each selected bookmark. + for (long databaseIdLong : selectedBookmarksIdsLongArray) { + // Convert `databaseIdLong` to an int. + int databaseIdInt = (int) databaseIdLong; + + // Delete the selected bookmark. + bookmarksDatabaseHelper.deleteBookmark(databaseIdInt); + } + } + + // Reset the deleting bookmarks flag. + deletingBookmarks = false; + + // Enable the delete menu item. + deleteMenuItem.setEnabled(true); + + // Close the activity if back has been pressed. + if (closeActivityAfterDismissingSnackbar) { + onBackPressed(); + } + } + }); + + // Show the Snackbar. + bookmarksDeletedSnackbar.show(); + break; + } + + // Consume the click. + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Do nothing. + } + }); } @Override @@ -304,8 +525,8 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements switch (menuItemId) { case android.R.id.home: // The home arrow is identified as `android.R.id.home`, not just `R.id.home`. - // Return to `MainWebViewActivity`. - NavUtils.navigateUpFromSameTask(this); + // Exit the activity. + onBackPressed(); break; case R.id.options_menu_sort: @@ -345,24 +566,59 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements return true; } + @Override + public void onBackPressed() { + // Check to see if a snackbar is currently displayed. If so, it must be closed before existing so that a pending delete is completed before reloading the list view in the bookmarks activity. + if ((bookmarksDeletedSnackbar != null) && bookmarksDeletedSnackbar.isShown()) { // Close the bookmarks deleted snackbar before going home. + // Set the close flag. + closeActivityAfterDismissingSnackbar = true; + + // Dismiss the snackbar. + bookmarksDeletedSnackbar.dismiss(); + } else { // Go home immediately. + // Update the current folder in the bookmarks activity. + switch (currentFolderDatabaseId) { + case ALL_FOLDERS_DATABASE_ID: + // Load the home folder. + BookmarksActivity.currentFolder = ""; + break; + + case HOME_FOLDER_DATABASE_ID: + // Load the home folder. + BookmarksActivity.currentFolder = ""; + break; + + default: + // Load the current folder. + BookmarksActivity.currentFolder = currentFolderName; + } + + // Reload the bookmarks list view when returning to the bookmarks activity. + BookmarksActivity.restartFromBookmarksDatabaseViewActivity = true; + + // Exit the bookmarks database view activity. + super.onBackPressed(); + } + } + private void updateBookmarksListView() { // Populate the bookmarks list view based on the spinner selection. switch (currentFolderDatabaseId) { // Get a cursor with all the folders. case ALL_FOLDERS_DATABASE_ID: if (sortByDisplayOrder) { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(); + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksByDisplayOrder(); } else { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(); + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarks(); } break; // Get a cursor for the home folder. case HOME_FOLDER_DATABASE_ID: if (sortByDisplayOrder) { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(""); + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(""); } else { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(""); + bookmarksCursor = bookmarksDatabaseHelper.getBookmarks(""); } break; @@ -370,9 +626,9 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements default: // Get a cursor for the selected folder. if (sortByDisplayOrder) { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentFolderName); + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentFolderName); } else { - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(currentFolderName); + bookmarksCursor = bookmarksDatabaseHelper.getBookmarks(currentFolderName); } } @@ -380,6 +636,54 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements bookmarksCursorAdapter.changeCursor(bookmarksCursor); } + private void selectAllBookmarksInFolder(int folderId) { + // Get a handle for the bookmarks list view. + ListView bookmarksListView = findViewById(R.id.bookmarks_databaseview_listview); + + // Get the folder name. + String folderName = bookmarksDatabaseHelper.getFolderName(folderId); + + // Get a cursor with the contents of the folder. + Cursor folderCursor = bookmarksDatabaseHelper.getBookmarks(folderName); + + // Move to the beginning of the cursor. + folderCursor.moveToFirst(); + + while (folderCursor.getPosition() < folderCursor.getCount()) { + // Get the bookmark database ID. + int bookmarkId = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper._ID)); + + // Move the bookmarks cursor to the first position. + bookmarksCursor.moveToFirst(); + + // Initialize the bookmark position variable. + int bookmarkPosition = -1; + + // Get the position of this bookmark in the bookmarks cursor. + while ((bookmarkPosition < 0) && (bookmarksCursor.getPosition() < bookmarksCursor.getCount())) { + // Check if the bookmark IDs match. + if (bookmarkId == bookmarksCursor.getInt(bookmarksCursor.getColumnIndex(BookmarksDatabaseHelper._ID))) { + // Get the bookmark position. + bookmarkPosition = bookmarksCursor.getPosition(); + + // If this bookmark is a folder, select all the bookmarks inside it. + if (bookmarksDatabaseHelper.isFolder(bookmarkId)) { + selectAllBookmarksInFolder(bookmarkId); + } + + // Select the bookmark. + bookmarksListView.setItemChecked(bookmarkPosition, true); + } + + // Increment the bookmarks cursor position. + bookmarksCursor.moveToNext(); + } + + // Move to the next position. + folderCursor.moveToNext(); + } + } + @Override public void onSaveBookmark(AppCompatDialogFragment dialogFragment, int selectedBookmarkDatabaseId) { // Get handles for the views from dialog fragment. diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java index 647cdb71..c1463d92 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.java @@ -769,7 +769,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Update `findOnPageCountTextView`. mainWebView.setFindListener(new WebView.FindListener() { // Get a handle for `findOnPageCountTextView`. - final TextView findOnPageCountTextView = (TextView) findViewById(R.id.find_on_page_count_textview); + final TextView findOnPageCountTextView = findViewById(R.id.find_on_page_count_textview); @Override public void onFindResultReceived(int activeMatchOrdinal, int numberOfMatches, boolean isDoneCounting) { @@ -863,7 +863,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook int databaseID = (int) id; // Get the bookmark cursor for this ID and move it to the first row. - Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmarkCursor(databaseID); + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(databaseID); bookmarkCursor.moveToFirst(); // Act upon the bookmark according to the type. @@ -3488,8 +3488,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create the bookmark. bookmarksDatabaseHelper.createBookmark(bookmarkNameString, bookmarkUrlString, currentBookmarksFolder, newBookmarkDisplayOrder, favoriteIconByteArray); - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -3533,8 +3533,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook // Create the folder, which will be placed at the top of the `ListView`. bookmarksDatabaseHelper.createFolder(folderNameString, currentBookmarksFolder, folderIconByteArray); - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -3748,8 +3748,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook bookmarksDatabaseHelper.updateBookmark(selectedBookmarkDatabaseId, bookmarkNameString, bookmarkUrlString, newFavoriteIconByteArray); } - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -3810,8 +3810,8 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook bookmarksDatabaseHelper.updateFolder(selectedFolderDatabaseId, oldFolderNameString, newFolderNameString, folderIconByteArray); } - // Update `bookmarksCursor` with the current contents of this folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder); + // Update the bookmarks cursor with the current contents of this folder. + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder); // Update the `ListView`. bookmarksCursorAdapter.changeCursor(bookmarksCursor); @@ -3902,7 +3902,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook drawerLayout.closeDrawer(GravityCompat.END); } else { // A subfolder is displayed. // Place the former parent folder in `currentFolder`. - currentBookmarksFolder = bookmarksDatabaseHelper.getParentFolder(currentBookmarksFolder); + currentBookmarksFolder = bookmarksDatabaseHelper.getParentFolderName(currentBookmarksFolder); // Load the new folder. loadBookmarksFolder(); @@ -4745,7 +4745,7 @@ public class MainWebViewActivity extends AppCompatActivity implements CreateBook private void loadBookmarksFolder() { // Update the bookmarks cursor with the contents of the bookmarks database for the current folder. - bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursorByDisplayOrder(currentBookmarksFolder); + bookmarksCursor = bookmarksDatabaseHelper.getBookmarksByDisplayOrder(currentBookmarksFolder); // Populate the bookmarks cursor adapter. `this` specifies the `Context`. `false` disables `autoRequery`. bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) { diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java index 670d237b..a7a96616 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -140,7 +140,7 @@ public class CreateBookmarkFolderDialog extends AppCompatDialogFragment { String folderName = s.toString(); // Check if a folder with the name already exists. - Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolderCursor(folderName); + Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(folderName); // Enable the create button if the new folder name is not empty and doesn't already exist. createButton.setEnabled(!folderName.isEmpty() && (folderExistsCursor.getCount() == 0)); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java index 272e4719..7328080e 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -115,7 +115,7 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment { BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a cursor with the selected bookmark and move it to the first position. - Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmarkCursor(bookmarkDatabaseId); + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(bookmarkDatabaseId); bookmarkCursor.moveToFirst(); // Use an alert dialog builder to create the alert dialog. @@ -207,7 +207,7 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment { matrixCursor.addRow(new Object[]{HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)}); // Get a `Cursor` with the list of all the folders. - Cursor foldersCursor = bookmarksDatabaseHelper.getAllFoldersCursor(); + Cursor foldersCursor = bookmarksDatabaseHelper.getAllFolders(); // Combine `matrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java index 27be599c..0bb5f9da 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -100,7 +100,7 @@ public class EditBookmarkDialog extends AppCompatDialogFragment { BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a `Cursor` with the selected bookmark and move it to the first position. - Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmarkCursor(selectedBookmarkDatabaseId); + Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(selectedBookmarkDatabaseId); bookmarkCursor.moveToFirst(); // Use an alert dialog builder to create the alert dialog. diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java index c2d44cd0..75e0d916 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -114,7 +114,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a `Cursor` with the selected bookmark and move it to the first position. - Cursor folderCursor = bookmarksDatabaseHelper.getBookmarkCursor(folderDatabaseId); + Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(folderDatabaseId); folderCursor.moveToFirst(); // Use an alert dialog builder to create the alert dialog. @@ -210,7 +210,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen addSubfoldersToExceptFolders(currentFolderName); // Get a `Cursor` with the list of all the folders. - Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersCursorExcept(exceptFolders.toString()); + Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders.toString()); // Combine `matrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); @@ -373,7 +373,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen String newDisplayOrder = displayOrderEditText.getText().toString(); // Get a cursor for the new folder name if it exists. - Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolderCursor(newFolderName); + Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName); // Is the new folder name empty? boolean folderNameNotEmpty = !newFolderName.isEmpty(); @@ -402,7 +402,7 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen private void addSubfoldersToExceptFolders(String folderName) { // Get a `Cursor` will all the immediate subfolders. - Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfoldersCursor(folderName); + Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfolders(folderName); for (int i = 0; i < subfoldersCursor.getCount(); i++) { // Move `subfolderCursor` to the current item. diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java index 0ef29c74..e854a065 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -94,7 +94,7 @@ public class EditBookmarkFolderDialog extends AppCompatDialogFragment { final BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0); // Get a `Cursor` with the selected folder and move it to the first position. - Cursor folderCursor = bookmarksDatabaseHelper.getBookmarkCursor(selectedFolderDatabaseId); + Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(selectedFolderDatabaseId); folderCursor.moveToFirst(); // Use an alert dialog builder to create the alert dialog. @@ -189,7 +189,7 @@ public class EditBookmarkFolderDialog extends AppCompatDialogFragment { String newFolderName = s.toString(); // Get a cursor for the new folder name if it exists. - Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolderCursor(newFolderName); + Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName); // Is the new folder name empty? boolean folderNameNotEmpty = !newFolderName.isEmpty(); @@ -214,7 +214,7 @@ public class EditBookmarkFolderDialog extends AppCompatDialogFragment { String newFolderName = folderNameEditText.getText().toString(); // Get a cursor for the new folder name if it exists. - Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolderCursor(newFolderName); + Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName); // Is the new folder name empty? boolean folderNameEmpty = newFolderName.isEmpty(); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java index 2bbd4e66..51495344 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -166,12 +166,15 @@ public class MoveToFolderDialog extends AppCompatDialogFragment { } // Get a `Cursor` containing the folders to display. - foldersCursor = bookmarksDatabaseHelper.getFoldersCursorExcept(exceptFolders.toString()); + foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders.toString()); // Setup `foldersCursorAdaptor` with `this` context. `false` disables autoRequery. foldersCursorAdapter = new CursorAdapter(alertDialog.getContext(), foldersCursor, false) { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { + // Remove the incorrect lint warning that `.getLayoutInflator()` might be false. + assert getActivity() != null; + // Inflate the individual item layout. `false` does not attach it to the root. return getActivity().getLayoutInflater().inflate(R.layout.move_to_folder_item_linearlayout, parent, false); } @@ -233,7 +236,7 @@ public class MoveToFolderDialog extends AppCompatDialogFragment { } // Get a `Cursor` containing the folders to display. - foldersCursor = bookmarksDatabaseHelper.getFoldersCursorExcept(exceptFolders.toString()); + foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders.toString()); // Combine `homeFolderMatrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{homeFolderMatrixCursor, foldersCursor}); @@ -242,6 +245,9 @@ public class MoveToFolderDialog extends AppCompatDialogFragment { foldersCursorAdapter = new CursorAdapter(alertDialog.getContext(), foldersMergeCursor, false) { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { + // Remove the incorrect lint warning that `.getLayoutInflator()` might be false. + assert getActivity() != null; + // Inflate the individual item layout. `false` does not attach it to the root. return getActivity().getLayoutInflater().inflate(R.layout.move_to_folder_item_linearlayout, parent, false); } @@ -280,7 +286,7 @@ public class MoveToFolderDialog extends AppCompatDialogFragment { private void addSubfoldersToExceptFolders(String folderName) { // Get a `Cursor` will all the immediate subfolders. - Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfoldersCursor(folderName); + Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfolders(folderName); for (int i = 0; i < subfoldersCursor.getCount(); i++) { // Move `subfolderCursor` to the current item. diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java index ad97e38c..85089314 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java @@ -121,7 +121,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { } // Get a `Cursor` for the bookmark with the specified database ID. - public Cursor getBookmarkCursor(int databaseId) { + public Cursor getBookmark(int databaseId) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -157,7 +157,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return folderName; } - // The the database ID for the specified folder name. + // Get the database ID for the specified folder name. public int getFolderDatabaseId (String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -185,8 +185,8 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return databaseId; } - // Get a `Cursor` for the specified folder name. - public Cursor getFolderCursor(String folderName) { + // Get a cursor for the specified folder name. + public Cursor getFolder(String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -203,8 +203,8 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return bookmarksDatabase.rawQuery(GET_FOLDER, null); } - // Get a `Cursor` of all the folders except those specified. - public Cursor getFoldersCursorExcept(String exceptFolders) { + // Get a cursor of all the folders except those specified. + public Cursor getFoldersExcept(String exceptFolders) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -219,8 +219,8 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return bookmarksDatabase.rawQuery(GET_FOLDERS_EXCEPT, null); } - // Get a `Cursor` with all the subfolders of the specified folder. - public Cursor getSubfoldersCursor(String currentFolder) { + // Get a cursor with all the subfolders of the specified folder. + public Cursor getSubfolders(String currentFolder) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -237,34 +237,56 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return bookmarksDatabase.rawQuery(GET_SUBFOLDERS, null); } - // Get a `String` with the name of the parent folder. - public String getParentFolder(String currentFolder) { + // Get the name of the parent folder. + public String getParentFolderName(String currentFolder) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); // SQL escape `currentFolder`. currentFolder = DatabaseUtils.sqlEscapeString(currentFolder); - // Prepare the SQL statement to get the parent folder. - String GET_PARENT_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE + + // Prepare the SQL statement to get the current folder. + String GET_CURRENT_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE + " WHERE " + IS_FOLDER + " = " + 1 + " AND " + BOOKMARK_NAME + " = " + currentFolder; // Get the bookmark cursor and move to the first entry. - Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_PARENT_FOLDER, null); + Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_CURRENT_FOLDER, null); bookmarkCursor.moveToFirst(); // Store the name of the parent folder. String parentFolder = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(PARENT_FOLDER)); - // Close the `Cursor`. + // Close the cursor. bookmarkCursor.close(); return parentFolder; } - // Get a `Cursor` of all the folders. - public Cursor getAllFoldersCursor() { + // Get the name of the parent folder. + public String getParentFolderName(int databaseId) { + // Get a readable database handle. + SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); + + // Prepare the SQL statement to get the current bookmark. + String GET_BOOKMARK = "SELECT * FROM " + BOOKMARKS_TABLE + + " WHERE " + _ID + " = " + databaseId; + + // Get the bookmark cursor and move to the first entry. + Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_BOOKMARK, null); + bookmarkCursor.moveToFirst(); + + // Store the name of the parent folder. + String parentFolder = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(PARENT_FOLDER)); + + // Close the cursor. + bookmarkCursor.close(); + + return parentFolder; + } + + // Get a cursor of all the folders. + public Cursor getAllFolders() { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -279,7 +301,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { } // Get a cursor for all bookmarks and folders. - public Cursor getAllBookmarksCursor() { + public Cursor getAllBookmarks() { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -290,8 +312,74 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null); } - // Get a `Cursor` for all bookmarks and folders in the specified folder. - public Cursor getAllBookmarksCursor(String folderName) { + // Get a cursor for all bookmarks and folders ordered by display order. + public Cursor getAllBookmarksByDisplayOrder() { + // Get a readable database handle. + SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); + + // Get everything in the bookmarks table ordered by display order. + String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + " ORDER BY " + DISPLAY_ORDER + " ASC"; + + // Return the result as a cursor. The cursor cannot be closed because it is used in the parent activity. + return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null); + } + + // Get a cursor for all bookmarks and folders except those with the specified IDs. + public Cursor getAllBookmarksExcept(long[] exceptIdLongArray) { + // Get a readable database handle. + SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); + + // Prepare a string builder to contain the comma-separated list of IDs not to get. + StringBuilder idsNotToGetStringBuilder = new StringBuilder(); + + // Extract the array of IDs not to get to the string builder. + for (long databaseIdLong : exceptIdLongArray) { + if (idsNotToGetStringBuilder.length() == 0) { // This is the first number, so only add the number. + idsNotToGetStringBuilder.append(databaseIdLong); + } else { // This is not the first number, so place a `,` before the new number. + idsNotToGetStringBuilder.append(","); + idsNotToGetStringBuilder.append(databaseIdLong); + } + } + + // Prepare the SQL statement to select all items except those with the specified IDs. + String GET_ALL_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE + + " WHERE " + _ID + " NOT IN (" + idsNotToGetStringBuilder.toString() + ")"; + + // Return the results as a cursor. The cursor cannot be closed because it will be used in the parent activity. + return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS_EXCEPT_SPECIFIED, null); + } + + // Get a cursor for all bookmarks and folders by display order except for a specific of IDs. + public Cursor getAllBookmarksByDisplayOrderExcept(long[] exceptIdLongArray) { + // Get a readable database handle. + SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); + + // Prepare a string builder to contain the comma-separated list of IDs not to get. + StringBuilder idsNotToGetStringBuilder = new StringBuilder(); + + // Extract the array of IDs not to get to the string builder. + for (long databaseIdLong : exceptIdLongArray) { + if (idsNotToGetStringBuilder.length() == 0) { // This is the first number, so only add the number. + idsNotToGetStringBuilder.append(databaseIdLong); + } else { // This is not the first number, so place a `,` before the new number. + idsNotToGetStringBuilder.append(","); + idsNotToGetStringBuilder.append(databaseIdLong); + } + } + + // Prepare the SQL statement to select all items except those with the specified IDs. + String GET_ALL_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE + + " WHERE " + _ID + " NOT IN (" + idsNotToGetStringBuilder.toString() + + ") ORDER BY " + DISPLAY_ORDER + " ASC"; + + // Return the results as a cursor. The cursor cannot be closed because it will be used in the parent activity. + return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS_EXCEPT_SPECIFIED, null); + } + + // Get a cursor for bookmarks and folders in the specified folder. + public Cursor getBookmarks(String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); @@ -299,59 +387,75 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { folderName = DatabaseUtils.sqlEscapeString(folderName); // Get everything in the bookmarks table with `folderName` as the `PARENT_FOLDER`. - String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + String GET_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + " WHERE " + PARENT_FOLDER + " = " + folderName; // Return the result as a cursor. The cursor cannot be closed because it is used in the parent activity. - return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null); + return bookmarksDatabase.rawQuery(GET_BOOKMARKS, null); } - // Get a cursor for all bookmarks and folders ordered by display order. - public Cursor getAllBookmarksCursorByDisplayOrder() { + // Get a cursor for bookmarks and folders in the specified folder ordered by display order. + public Cursor getBookmarksByDisplayOrder(String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); - // Get everything in the bookmarks table ordered by display order. - String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + // SQL escape `folderName`. + folderName = DatabaseUtils.sqlEscapeString(folderName); + + // Get everything in the bookmarks table with `folderName` as the `PARENT_FOLDER`. + String GET_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + " WHERE " + PARENT_FOLDER + " = " + folderName + " ORDER BY " + DISPLAY_ORDER + " ASC"; // Return the result as a cursor. The cursor cannot be closed because it is used in the parent activity. - return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null); + return bookmarksDatabase.rawQuery(GET_BOOKMARKS, null); } - // Get a cursor for all bookmarks and folders in the specified folder ordered by display order. - public Cursor getAllBookmarksCursorByDisplayOrder(String folderName) { + // Get a cursor for bookmarks and folders in the specified folder except for ta specific list of IDs. + public Cursor getBookmarksExcept(long[] exceptIdLongArray, String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); - // SQL escape `folderName`. + // Prepare a string builder to contain the comma-separated list of IDs not to get. + StringBuilder idsNotToGetStringBuilder = new StringBuilder(); + + // Extract the array of IDs not to get to the string builder. + for (long databaseIdLong : exceptIdLongArray) { + if (idsNotToGetStringBuilder.length() == 0) { // This is the first number, so only add the number. + idsNotToGetStringBuilder.append(databaseIdLong); + } else { // This is not the first number, so place a `,` before the new number. + idsNotToGetStringBuilder.append(","); + idsNotToGetStringBuilder.append(databaseIdLong); + } + } + + // SQL escape the folder name. folderName = DatabaseUtils.sqlEscapeString(folderName); - // Get everything in the bookmarks table with `folderName` as the `PARENT_FOLDER`. - String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + // Get everything in the bookmarks table with `folderName` as the `PARENT_FOLDER` except those with the specified IDs. + String GET_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE + " WHERE " + PARENT_FOLDER + " = " + folderName + - " ORDER BY " + DISPLAY_ORDER + " ASC"; + " AND " + _ID + " NOT IN (" + idsNotToGetStringBuilder.toString() + ")"; // Return the result as a cursor. The cursor cannot be closed because it is used in the parent activity. - return bookmarksDatabase.rawQuery(GET_ALL_BOOKMARKS, null); + return bookmarksDatabase.rawQuery(GET_BOOKMARKS_EXCEPT_SPECIFIED, null); } - // Get a `Cursor` for all bookmarks and folders in the specified folder except for a specific list of IDs. - public Cursor getBookmarksCursorExcept(long[] exceptIdLongArray, String folderName) { + // Get a cursor for bookmarks and folders in the specified folder by display order except for a specific list of IDs. + public Cursor getBookmarksByDisplayOrderExcept(long[] exceptIdLongArray, String folderName) { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); - // Prepare a string builder that contains the comma-separated list of IDs not to get. - StringBuilder doNotGetIdsStringBuilder = new StringBuilder(); + // Prepare a string builder to contain the comma-separated list of IDs not to get. + StringBuilder idsNotToGetStringBuilder = new StringBuilder(); - // Extract the array to `doNotGetIdsString`. + // Extract the array of IDs not to get to the string builder. for (long databaseIdLong : exceptIdLongArray) { - // If this is the first number, only add the number. - if (doNotGetIdsStringBuilder.toString().isEmpty()) { - doNotGetIdsStringBuilder.append(databaseIdLong); - } else { // If there already is a number in the string, place a `,` before the new number. - doNotGetIdsStringBuilder.append(","); - doNotGetIdsStringBuilder.append(databaseIdLong); + if (idsNotToGetStringBuilder.length() == 0) { // This is the first number, so only add the number. + idsNotToGetStringBuilder.append(databaseIdLong); + } else { // This is not the first number, so place a `,` before the new number. + idsNotToGetStringBuilder.append(","); + idsNotToGetStringBuilder.append(databaseIdLong); } } @@ -359,14 +463,13 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { folderName = DatabaseUtils.sqlEscapeString(folderName); // Prepare the SQL statement to select all items except those with the specified IDs. - String GET_All_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE + + String GET_BOOKMARKS_EXCEPT_SPECIFIED = "SELECT * FROM " + BOOKMARKS_TABLE + " WHERE " + PARENT_FOLDER + " = " + folderName + - " AND " + _ID + " NOT IN (" + doNotGetIdsStringBuilder.toString() + + " AND " + _ID + " NOT IN (" + idsNotToGetStringBuilder.toString() + ") ORDER BY " + DISPLAY_ORDER + " ASC"; - // Return the results as a `Cursor`. The second argument is `null` because there are no `selectionArgs`. - // We can't close the `Cursor` because we need to use it in the parent activity. - return bookmarksDatabase.rawQuery(GET_All_BOOKMARKS_EXCEPT_SPECIFIED, null); + // Return the results as a cursor. The cursor cannot be closed because it will be used in the parent activity. + return bookmarksDatabase.rawQuery(GET_BOOKMARKS_EXCEPT_SPECIFIED, null); } // Check if a database ID is a folder. @@ -378,14 +481,14 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { String CHECK_IF_FOLDER = "SELECT * FROM " + BOOKMARKS_TABLE + " WHERE " + _ID + " = " + databaseId; - // Populate folderCursor. The second argument is `null` because there are no `selectionArgs`. + // Populate the folder cursor. Cursor folderCursor = bookmarksDatabase.rawQuery(CHECK_IF_FOLDER, null); // Ascertain if this database ID is a folder. folderCursor.moveToFirst(); boolean isFolder = (folderCursor.getInt(folderCursor.getColumnIndex(IS_FOLDER)) == 1); - // Close the `Cursor` and the database handle. + // Close the cursor and the database handle. folderCursor.close(); bookmarksDatabase.close(); @@ -394,7 +497,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { // Update the bookmark name and URL. public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl) { - // Initialize a `ContentValues`. + // Initialize a ContentValues. ContentValues bookmarkContentValues = new ContentValues(); // Store the updated values. diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java index 6af6166f..bcec5294 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/ImportExportDatabaseHelper.java @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Soren Stoutner . + * Copyright © 2018-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -158,7 +158,7 @@ public class ImportExportDatabaseHelper { BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(context, null, null, 0); // Get a full bookmarks cursor. - Cursor bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(); + Cursor bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarks(); // Move to the first bookmark. bookmarksCursor.moveToFirst(); diff --git a/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml b/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml index 903537aa..378a71e1 100644 --- a/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml +++ b/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml @@ -1,7 +1,7 @@ + android:layout_width="match_parent" + android:choiceMode="multipleChoiceModal" /> \ No newline at end of file diff --git a/app/src/main/res/layout/bookmarks_databaseview_item_linearlayout.xml b/app/src/main/res/layout/bookmarks_databaseview_item_linearlayout.xml index bc00f778..7911f31d 100644 --- a/app/src/main/res/layout/bookmarks_databaseview_item_linearlayout.xml +++ b/app/src/main/res/layout/bookmarks_databaseview_item_linearlayout.xml @@ -1,7 +1,7 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce453359..628cc795 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -231,6 +231,9 @@ Просмотр базы данных закладок Все папки Домашняя папка + Сортировка + Сортировать по ID базы данных. + Сортировать по порядку отображения. ID базы данных: Папка: Родительская папка: diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index ff7d0567..40922729 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -22,7 +22,7 @@ Privacy Browser Privacy Browser Ayarları - + tr @@ -103,7 +103,7 @@ Açılır Menü - Gezinim + Gezinti Anasayfa Geri İleri @@ -230,12 +230,46 @@ Yer İmleri Veritabanı Görünümü Tüm Klasörler Ana klasör + Sırala + Veritabanı kimliğine göre sıralandı. + Görüntüleme düzenine göre sıralandı. Veritabanı Kimliği: Klasör: Üst Klasör: - Display order: + Görüntüleme düzeni: + İstekler + İstek detayları + İşlem + Tüm + Varsayılan + Varsayılan - İzin verildi + İzin verildi + İzin verildi + Üçüncü Taraflar + Üçüncü Taraf - Engellendi + Engellendi + Engellendi + Engellenenler + Ana beyaz liste + Final beyaz liste + Domain beyaz listesi + Domain başlangıç beyaz listesi + Domain final beyaz listesi + Üçüncü taraf beyaz listesi + Üçüncü taraf domain beyaz listesi + Üçüncü taraf domain başlangıç beyaz listesi + Ana kara liste + Başlangıç kara listesi + Final kara liste + Domain kara listesi + Domain başlangıç kara listesi + Domain final kara listesi + Üçüncü taraf kara listesi + Üçüncü taraf başlangıç kara listesi + Üçüncü taraf domain kara listesi + Üçüncü taraf domain başlangıç kara listesi Domainler @@ -248,17 +282,17 @@ Sistem varsayılanı Yenilemek için kaydır etkin - Yenilemek için kaydır devredışı + Yenilemek için kaydır devre dışı Sistem varsayılanı Gece modu etkin - Gece modu devredışı + Gece modu devre dışı Sistem varsayılanı - Görüntüler etkin - Görüntüler devredışı + Resimler etkin + Resimler devre dışı İğneli SSL sertifikası Kayıtlı SSL sertifikası @@ -268,16 +302,22 @@ Privacy Browser Rehberi - Yerel Depolama + Genel Bakış + Yerel Depolama Alanı SSL Sertifikaları + İzleme Kimlikleri İndirme Konumu - OK + Privacy Browser\'ın genel indirme dizinini kullanması için depolama alanı izni gerekmektedir. + Eğer reddedilirse, onun yerine uygulamanın indirme dizini kullanılacaktır. + Orbot yüklenmeden Orbot proxy çalışmayacaktır. + Orbot\'un bağlanması bekleniyor... + Privacy Browser Hakkında Sürüm Sürüm kodu Donanım @@ -285,10 +325,11 @@ Üretici: Cihaz: Bootloader: - Radio: + Donanım Yazılımı: Yazılım Android: API + Derleme: Güvenlik Yaması: Web Görünümü: Orbot: @@ -298,16 +339,32 @@ Fanboy’s Annoyance Listesi: Fanboy’s Social Blocking Listesi: UltraPrivacy: + Paket İmzası + Yayınlayan DA: + Özne DA: Sertifika Sürümü: - Serial Number: + Seri Numarası: İmza Algoritması: İzinler + Privacy Politikası Değişiklik Günlüğü Lisanslar Katkıda Bulunanlar Linkler + Gizlilik + JavaScript\'i varsayılan olarak etkinleştir + JavaScript web sitelerin cihazdaki programları(scriptler) çalıştırmasına izin verir. + Birinci taraf çerezleri varsayılan olarak etkinleştir + Bu ayar, Android Lollipop sürümünden(5.0) eski sürümlere sahip cihazlarda üçüncü taraf çerezleri de etkinleştirir. + Üçüncü taraf çerezleri varsayılan olarak etkinleştir + Bu ayarı etkinleştirmek için Android Lollipop sürümüne(5.0) ya da daha üst sürümlere sahip olmak gerekir. + Birinci taraf çerezler devre dışı olduğu takdirde etkisi yoktur. + DOM depolama alanını varsayılan olarak etkinleştir + DOM depolama alanının çalışması için JavaScript\'in etkin olması gerekir. + Form verisini kaydetmeyi varsayılan olarak etkinleştir + Kaydedilen form verisi web sitelerdeki boşlukları otomatik dolduracaktır. Kullanıcı aracısı Privacy Browser @@ -341,11 +398,31 @@ Özel Özel kullanıcı aracısı + Gizli Mod + Her web sayfasının yüklenmesi bittikten sonra geçmişi ve önbelleği temizler. İleri ve geri seçenekleri Gizli Mod aktifken çalışmaz. + Takip Etme + Web Serverlarına, bu tarayıcıyı takip etmemesini nezaketle telkin etmek için Takip Etme Başlığı gönderir. + Ekran görüntülerine izin ver + Ekran görüntülerine, video kaydına ve güvenli olmayan ekranlarda görüntülenmeye izin verir. + Bu ayarı değiştirmek Privacy Browser uygulamasını yeniden başlatır. + Engellenenler + EasyList + Ana reklam engelleme listesi. + EasyPrivacy + Ana takipçi engelleme listesi. + Fanboy’s annoyance listesi + Rahatsız eden popupları ve linkleri engeller. Fanboy’s social blocking listesini de içerir. + Fanboy’s social blocking listesi + Üçüncü taraf sosyal medya içeriklerini engeller. + UltraPrivacy + UltraPrivacy, EasyPrivacy\'de olmayan takipçileri de engeller fakat bu seçenek bazı web sitelerinin çökmesine sebep olabilir. + Tüm üçüncü taraf istekleri engelle + Tüm üçüncü taraf istekleri engellemek gizliliği arttırır, fakat çoğu web sitesinin çökmesine sebep olur. Searx DuckDuckGo - JavaScript devre dışı DuckDuckGo - JavaScript etkin - Custom + Özel Arama @@ -361,6 +438,24 @@ Yahoo - JavaScript etkin Özel + Özel URL Ara + Özel URL + Tam Ekran + Tam ekran modu + Tam ekran moduna geçmek için çift dokun. + Sistem çubuğunu gizle + Tam ekran modunda durum ve gezinti çubuğunu gizler. Tam ekran modundayken klavye açıldığında iyi çalışmayabilir. + Yarı saydam gezinti çubuğu + Gezinti çubuğunu, tam ekran modunda yarı saydam yapar. + Her şeyi temizle + Çerezleri temizle + Birinci ve Üçüncü taraf çerezleri temizler + Dom Depolama Alanını temizle + Dom Depolama Alanını temizler. + Form verisini temizle + Form verisini temizler. + Önbelleği temizle + Web Görünümü önbelleğini temizler. Genel Ana Sayfa Yazı tipi boyutu @@ -375,7 +470,7 @@ %200 - System default + Sistem varsayılanı %25 %50 %75 @@ -386,8 +481,16 @@ %200 Yenilemek için kaydır + Bazı web siteleri, yenilemek için kaydır seçeneği etkin olduğunda iyi çalışmayabilir. + Harici uygulamayla indir + Android indirme yönetecisi bazı cihazlarda iyi çalışmayabilir. + Ek uygulama çubuğu simgelerini göster Koyu tema + Temayı değiştirmek Privacy Browser\'ı yeniden başlatacak. Gece mody + Gece modunu etkinleştirmek aynı zamanda tüm sitelerde JavaScript\'i etkinleştirecek. + Web sitesi resimlerini göster + Bant genişliği korumayı devre dışı bırak. Reklam Onayı diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 19e2bc83..a5dece77 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -246,6 +246,7 @@ Folder: Parent folder: Display order: + A bookmark cannot be deselected while the parent folder is selected. Requests @@ -488,7 +489,7 @@ UltraPrivacy UltraPrivacy blocks trackers that EasyPrivacy doesn’t because doing so can break websites. Block all third-party requests - Blocking all third-party requests increases privacy, but it breaks many websites. + Blocking all third-party requests increases privacy, but it breaks many websites. Tor Proxy through Orbot Proxy all web traffic through Orbot on localhost:8118. -- 2.43.0