<w>orbot</w>
<w>panopticlick</w>
<w>parentfolder</w>
+ <w>programatically</w>
<w>radiobutton</w>
<w>radiogroup</w>
<w>redmine</w>
<w>securitypatch</w>
<w>snackbar</w>
<w>snackbars</w>
+ <w>subfolders</w>
<w>tablayout</w>
<w>techrepublic</w>
<w>textview</w>
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
-import android.database.DatabaseUtils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
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.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
-import android.widget.CheckBox;
+import android.widget.CursorAdapter;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
public class BookmarksActivity extends AppCompatActivity implements CreateBookmark.CreateBookmarkListener,
CreateBookmarkFolder.CreateBookmarkFolderListener, EditBookmark.EditBookmarkListener,
- EditBookmarkFolder.EditBookmarkFolderListener {
- // `bookmarksDatabaseHandler` is public static so it can be accessed from EditBookmark. It is also used in `onCreate()`,
+ EditBookmarkFolder.EditBookmarkFolderListener, MoveToFolder.MoveToFolderListener {
+ // `bookmarksDatabaseHandler` is public static so it can be accessed from `EditBookmark` and `MoveToFolder`. It is also used in `onCreate()`,
// `onCreateBookmarkCreate()`, `updateBookmarksListView()`, and `updateBookmarksListViewExcept()`.
public static BookmarksDatabaseHandler bookmarksDatabaseHandler;
- // `bookmarksListView` is public static so it can be accessed from EditBookmark.
+ // `bookmarksListView` is public static so it can be accessed from `EditBookmark`.
// It is also used in `onCreate()`, `updateBookmarksListView()`, and `updateBookmarksListViewExcept()`.
public static ListView bookmarksListView;
- // `currentFolder` is used in `onCreate`, `onOptionsItemSelected()`, `onCreateBookmarkCreate`, `onCreateBookmarkFolderCreate`, and `onEditBookmarkSave`.
- private String currentFolder;
+ // `currentFolder` is public static so it can be accessed from `MoveToFolder`.
+ // It is used in `onCreate`, `onOptionsItemSelected()`, `onCreateBookmarkCreate`, `onCreateBookmarkFolderCreate`, and `onEditBookmarkSave`.
+ public static String currentFolder;
// `contextualActionMode` is used in `onCreate()` and `onEditBookmarkSave()`.
private ActionMode contextualActionMode;
editBookmarkMenuItem = menu.findItem(R.id.edit_bookmark);
selectAllBookmarksMenuItem = menu.findItem(R.id.context_menu_select_all_bookmarks);
+ // Get a handle for `contextualActionMode` so we can close it programatically.
+ contextualActionMode = mode;
+
return true;
}
// Calculate the number of selected bookmarks.
int numberOfSelectedBookmarks = selectedBookmarksLongArray.length;
+ // Sometimes Android forgets to close the contextual app bar when all the items are deselected.
+ if (numberOfSelectedBookmarks == 0) {
+ mode.finish();
+ }
+
// List the number of selected bookmarks in the subtitle.
mode.setSubtitle(numberOfSelectedBookmarks + " " + getString(R.string.selected));
bookmarksListView.setSelection(selectedBookmarkNewPosition - 5);
break;
- case R.id.edit_bookmark:
- // Get a handle for `contextualActionMode` so we can close it when `editBookmarkDialog` is finished.
- contextualActionMode = mode;
+ case R.id.move_to_folder:
+ // Show the `MoveToFolder` `AlertDialog` and name the instance `@string/move_to_folder
+ DialogFragment moveToFolderDialog = new MoveToFolder();
+ moveToFolderDialog.show(getFragmentManager(), getResources().getString(R.string.move_to_folder));
+ break;
+ case R.id.edit_bookmark:
// Get a handle for `selectedBookmarkPosition` so we can scroll to it after refreshing the ListView.
bookmarkPositionSparseBooleanArray = bookmarksListView.getCheckedItemPositions();
- selectedBookmarkPosition = bookmarkPositionSparseBooleanArray.keyAt(0);
+ for (int i = 0; i < bookmarkPositionSparseBooleanArray.size(); i++) {
+ // Find the bookmark that is selected and save the position to `selectedBookmarkPosition`.
+ if (bookmarkPositionSparseBooleanArray.valueAt(i))
+ selectedBookmarkPosition = bookmarkPositionSparseBooleanArray.keyAt(i);
+ }
// Move to the selected database ID and find out if it is a folder.
bookmarksCursor.moveToPosition(selectedBookmarkPosition);
// Get a handle for `selectedBookmarkPosition` so we can scroll to it after refreshing the ListView.
bookmarkPositionSparseBooleanArray = bookmarksListView.getCheckedItemPositions();
- selectedBookmarkPosition = bookmarkPositionSparseBooleanArray.keyAt(0);
+ for (int i = 0; i < bookmarkPositionSparseBooleanArray.size(); i++) {
+ // Find the bookmark that is selected and save the position to `selectedBookmarkPosition`.
+ if (bookmarkPositionSparseBooleanArray.valueAt(i))
+ selectedBookmarkPosition = bookmarkPositionSparseBooleanArray.keyAt(i);
+ }
updateBookmarksListViewExcept(selectedBookmarksLongArray, currentFolder);
// Scroll to where the deleted bookmark was located.
- bookmarksListView.setSelection(selectedBookmarkPosition);
+ bookmarksListView.setSelection(selectedBookmarkPosition - 5);
String snackbarMessage;
// Refresh the ListView to show the rows again.
updateBookmarksListView(currentFolder);
+ // Scroll to where the deleted bookmark was located.
+ bookmarksListView.setSelection(selectedBookmarkPosition - 5);
+
break;
// The Snackbar was dismissed without the "Undo" button being pushed.
// Convert `databaseIdLong` to an int.
int databaseIdInt = (int) databaseIdLong;
- // Delete the database row.
+ if (bookmarksDatabaseHandler.isFolder(databaseIdInt)) {
+ deleteBookmarkFolderContents(databaseIdInt);
+ }
+
+ // Delete `databaseIdInt`.
bookmarksDatabaseHandler.deleteBookmark(databaseIdInt);
}
break;
int existingFoldersWithNewName = bookmarkFolderCursor.getCount();
bookmarkFolderCursor.close();
if ( ((existingFoldersWithNewName == 0) || newFolderNameString.equals(oldFolderNameString)) && !newFolderNameString.isEmpty()) {
- // Get a long array with the the databaseId of the selected folder and convert it to an `int`.
+ // Get a long array with the the database ID of the selected folder and convert it to an `int`.
long[] selectedFolderLongArray = bookmarksListView.getCheckedItemIds();
int selectedFolderDatabaseId = (int) selectedFolderLongArray[0];
}
}
+ @Override
+ public void onCancelMoveToFolder(DialogFragment dialogFragment) {
+ // Do nothing because the user selected `Cancel`.
+ }
+
+ @Override
+ public void onMoveToFolder(DialogFragment dialogFragment) {
+ // Get the new folder database id.
+ ListView folderListView = (ListView) dialogFragment.getDialog().findViewById(R.id.move_to_folder_listview);
+ long[] newFolderLongArray = folderListView.getCheckedItemIds();
+
+ if (newFolderLongArray.length == 0) { // No new folder was selected.
+ Snackbar.make(findViewById(R.id.bookmarks_coordinatorlayout), getString(R.string.cannot_move_bookmarks), Snackbar.LENGTH_LONG).show();
+ } else { // Move the selected bookmarks.
+ // Get the new folder database ID.
+ int newFolderDatabaseId = (int) newFolderLongArray[0];
+
+ // Instantiate `newFolderName`.
+ String newFolderName;
+
+ if (newFolderDatabaseId == 0) {
+ // The new folder is the home folder, represented as `""` in the database.
+ newFolderName = "";
+ } else {
+ // Get the new folder name from the database.
+ newFolderName = bookmarksDatabaseHandler.getFolderName(newFolderDatabaseId);
+ }
+
+ // Get a long array with the the database ID of the selected bookmarks.
+ long[] selectedBookmarksLongArray = bookmarksListView.getCheckedItemIds();
+ for (long databaseIdLong : selectedBookmarksLongArray) {
+ // Get `databaseIdInt` for each selected bookmark.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // Move the selected bookmark to the new folder.
+ bookmarksDatabaseHandler.moveToFolder(databaseIdInt, newFolderName);
+ }
+
+ // Refresh the `ListView`.
+ updateBookmarksListView(currentFolder);
+
+ // Close the contextual app bar.
+ contextualActionMode.finish();
+ }
+ }
+
private void updateBookmarksListView(String folderName) {
// Get a `Cursor` with the current contents of the bookmarks database.
bookmarksCursor = bookmarksDatabaseHandler.getAllBookmarksCursorByDisplayOrder(folderName);
- // Setup `bookmarksCursorAdapter` with `this` context. The `false` disables autoRequery.
+ // Setup `bookmarksCursorAdapter` with `this` context. `false` disables autoRequery.
CursorAdapter bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Get a `Cursor` with the current contents of the bookmarks database except for the specified database IDs.
bookmarksCursor = bookmarksDatabaseHandler.getBookmarksCursorExcept(exceptIdLongArray, folderName);
- // Setup `bookmarksCursorAdapter` with `this` context. The `false` disables autoRequery.
+ // Setup `bookmarksCursorAdapter` with `this` context. `false` disables autoRequery.
CursorAdapter bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Update the ListView.
bookmarksListView.setAdapter(bookmarksCursorAdapter);
}
+
+ private void deleteBookmarkFolderContents(int databaseId) {
+ // Get the name of the folder.
+ String folderName = bookmarksDatabaseHandler.getFolderName(databaseId);
+
+ // Get the contents of the folder.
+ Cursor folderCursor = bookmarksDatabaseHandler.getAllBookmarksCursorByDisplayOrder(folderName);
+
+ for (int i = 0; i < folderCursor.getCount(); i++) {
+ // Move `folderCursor` to the current row.
+ folderCursor.moveToPosition(i);
+
+ // Get the database ID of the item.
+ int itemDatabaseId = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHandler._ID));
+
+ // If this is a folder, delete the contents first.
+ if (bookmarksDatabaseHandler.isFolder(itemDatabaseId)) {
+ deleteBookmarkFolderContents(itemDatabaseId);
+ }
+
+ bookmarksDatabaseHandler.deleteBookmark(itemDatabaseId);
+ }
+ }
}
\ No newline at end of file
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.ContactsContract;
+import android.support.design.widget.Snackbar;
+import android.support.v4.content.ContextCompat;
public class BookmarksDatabaseHandler extends SQLiteOpenHelper {
private static final int SCHEMA_VERSION = 1;
return bookmarksDatabase.rawQuery(GET_ONE_BOOKMARK, null);
}
+ public String getFolderName (int databaseId) {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Prepare the SQL statement to get the `Cursor` for the folder.
+ final String GET_FOLDER = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + _ID + " = " + databaseId;
+
+ // Get `folderCursor`. The second argument is `null` because there are no `selectionArgs`.
+ Cursor folderCursor = bookmarksDatabase.rawQuery(GET_FOLDER, null);
+
+ // Get `folderName`.
+ folderCursor.moveToFirst();
+ String folderName = folderCursor.getString(folderCursor.getColumnIndex(BOOKMARK_NAME));
+
+ // Close the cursor and the database handle.
+ folderCursor.close();
+ bookmarksDatabase.close();
+
+ // Return the folder name.
+ return folderName;
+ }
+
public Cursor getFolderCursor(String folderName) {
// Get a readable database handle.
SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
return bookmarksDatabase.rawQuery(GET_FOLDER, null);
}
+ public Cursor getFoldersCursorExcept(String exceptFolders) {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Prepare the SQL statement to get the `Cursor` for the folders.
+ final String GET_FOLDERS_EXCEPT = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + IS_FOLDER + " = " + 1 +
+ " AND " + BOOKMARK_NAME + " NOT IN (" + exceptFolders +
+ ") ORDER BY " + BOOKMARK_NAME + " 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_FOLDERS_EXCEPT, null);
+ }
+
+ public Cursor getSubfoldersCursor(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 `Cursor` for the subfolders.
+ final String GET_SUBFOLDERS = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + PARENT_FOLDER + " = " + currentFolder +
+ " AND " + IS_FOLDER + " = " + 1;
+
+ // 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_SUBFOLDERS, null);
+ }
+
public String getParentFolder(String currentFolder) {
// Get a readable database handle.
SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
// Prepare the SQL statement to get the parent folder.
final String GET_PARENT_FOLDER = "Select * FROM " + BOOKMARKS_TABLE +
- " WHERE " + IS_FOLDER + " = " + 1 + " AND " + BOOKMARK_NAME + " = " + currentFolder;
+ " WHERE " + IS_FOLDER + " = " + 1 +
+ " AND " + BOOKMARK_NAME + " = " + currentFolder;
// The second argument is `null` because there are no `selectionArgs`.
Cursor bookmarkCursor = bookmarksDatabase.rawQuery(GET_PARENT_FOLDER, null);
// Get everything in the BOOKMARKS_TABLE.
final String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE +
- " WHERE " + PARENT_FOLDER + " = " + folderName + " ORDER BY " + DISPLAY_ORDER + " ASC";
+ " WHERE " + PARENT_FOLDER + " = " + folderName +
+ " 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.
// Prepare the SQL statement to select all items except those with the specified IDs.
final String GET_All_BOOKMARKS_EXCEPT_SPECIFIED = "Select * FROM " + BOOKMARKS_TABLE +
- " WHERE " + PARENT_FOLDER + " = " + folderName + " AND " + _ID + " NOT IN (" + doNotGetIdsString + ") ORDER BY " + DISPLAY_ORDER + " ASC";
+ " WHERE " + PARENT_FOLDER + " = " + folderName +
+ " AND " + _ID + " NOT IN (" + doNotGetIdsString +
+ ") ORDER BY " + DISPLAY_ORDER + " ASC";
- // Return the results as a `Cursor`. The second argument is `null` because there are no selectionArgs.
+ // 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);
}
+ public boolean isFolder(int databaseId) {
+ // Get a readable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getReadableDatabase();
+
+ // Prepare the SQL statement to determine if `databaseId` is a folder.
+ final String CHECK_IF_FOLDER = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + _ID + " = " + databaseId;
+
+ // Populate folderCursor. The second argument is `null` because there are no `selectionArgs`.
+ 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.
+ folderCursor.close();
+ bookmarksDatabase.close();
+
+ return isFolder;
+ }
+
public void updateBookmark(int databaseId, String bookmarkName, String bookmarkUrl) {
// Store the updated values in `bookmarkContentValues`.
ContentValues bookmarkContentValues = new ContentValues();
}
public void updateBookmarkDisplayOrder(int databaseId, int displayOrder) {
- // Store the updated values in `bookmarkContentValues`.
- ContentValues bookmarkContentValues = new ContentValues();
+ // Get a writable database handle.
+ SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
+ // Store the new display order in `bookmarkContentValues`.
+ ContentValues bookmarkContentValues = new ContentValues();
bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
+ // Update the database. The last argument is `null` because there are no `whereArgs`.
+ bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
+
+ // Close the database handle.
+ bookmarksDatabase.close();
+ }
+
+ public void moveToFolder(int databaseId, String newFolder) {
// Get a writable database handle.
SQLiteDatabase bookmarksDatabase = this.getWritableDatabase();
- // Update the database. The last argument is `null` because there are no `whereArgs`.
+ // Get the highest `DISPLAY_ORDER` in the new folder
+ String newFolderSqlEscaped = DatabaseUtils.sqlEscapeString(newFolder);
+ final String NEW_FOLDER = "Select * FROM " + BOOKMARKS_TABLE +
+ " WHERE " + PARENT_FOLDER + " = " + newFolderSqlEscaped +
+ " ORDER BY " + DISPLAY_ORDER + " ASC";
+ // The second argument is `null` because there are no `selectionArgs`.
+ Cursor newFolderCursor = bookmarksDatabase.rawQuery(NEW_FOLDER, null);
+ int displayOrder;
+ if (newFolderCursor.getCount() > 0) {
+ newFolderCursor.moveToLast();
+ displayOrder = newFolderCursor.getInt(newFolderCursor.getColumnIndex(DISPLAY_ORDER)) + 1;
+ } else {
+ displayOrder = 0;
+ }
+ newFolderCursor.close();
+
+ // Store the new values in `bookmarkContentValues`.
+ ContentValues bookmarkContentValues = new ContentValues();
+ bookmarkContentValues.put(DISPLAY_ORDER, displayOrder);
+ bookmarkContentValues.put(PARENT_FOLDER, newFolder);
+
+ // Update the database. The last argument is 'null' because there are no 'whereArgs'.
bookmarksDatabase.update(BOOKMARKS_TABLE, bookmarkContentValues, _ID + " = " + databaseId, null);
// Close the database handle.
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Inflate the individual item layout. `false` does not attach it to the root.
- return getLayoutInflater().inflate(R.layout.bookmarks_database_view_linearlayout, parent, false);
+ return getLayoutInflater().inflate(R.layout.bookmarks_database_view_item_linearlayout, parent, false);
}
@Override
// Get the parent folder from the `Cursor` and display it in `bookmarkParentFolder`.
String bookmarkParentFolder = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHandler.PARENT_FOLDER));
+ ImageView parentFolderImageView = (ImageView) view.findViewById(R.id.bookmarks_database_view_parent_folder_icon);
TextView bookmarkParentFolderTextView = (TextView) view.findViewById(R.id.bookmarks_database_view_parent_folder);
// Make the folder name gray if it is the home folder.
if (bookmarkParentFolder.isEmpty()) {
+ parentFolderImageView.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.folder_grey));
bookmarkParentFolderTextView.setText(R.string.home_folder);
bookmarkParentFolderTextView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.grey));
} else {
+ parentFolderImageView.setImageDrawable(ContextCompat.getDrawable(getApplicationContext(), R.drawable.folder_dark_blue));
bookmarkParentFolderTextView.setText(bookmarkParentFolder);
bookmarkParentFolderTextView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.black));
}
package com.stoutner.privacybrowser;
+import android.app.Activity;
+import android.app.Dialog;
import android.app.DialogFragment;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.MatrixCursor;
+import android.database.MergeCursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+// If we don't use `android.support.v7.app.AlertDialog` instead of `android.app.AlertDialog` then the dialog will be covered by the keyboard.
+import android.support.design.widget.Snackbar;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import java.io.ByteArrayOutputStream;
public class MoveToFolder extends DialogFragment {
+ // The public interface is used to send information back to the parent activity.
+ public interface MoveToFolderListener {
+ void onCancelMoveToFolder(DialogFragment dialogFragment);
+
+ void onMoveToFolder(DialogFragment dialogFragment);
+ }
+
+ // `moveToFolderListener` is used in `onAttach()` and `onCreateDialog`.
+ private MoveToFolderListener moveToFolderListener;
+
+ public void onAttach(Activity parentActivity) {
+ super.onAttach(parentActivity);
+
+ // Get a handle for `MoveToFolderListener` from `parentActivity`.
+ try {
+ moveToFolderListener = (MoveToFolderListener) parentActivity;
+ } catch(ClassCastException exception) {
+ throw new ClassCastException(parentActivity.toString() + " must implement EditBookmarkFolderListener.");
+ }
+ }
+
+ // `exceptFolders` is used in `onCreateDialog()` and `addSubfoldersToExceptFolders()`.
+ private String exceptFolders;
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ // Use `AlertDialog.Builder` to create the `AlertDialog`. The style formats the color of the button text.
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.LightAlertDialog);
+ dialogBuilder.setTitle(R.string.move_to_folder);
+ // The parent view is `null` because it will be assigned by `AlertDialog`.
+ dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.move_to_folder_dialog, null));
+
+ // Set an `onClick()` listener for the negative button.
+ dialogBuilder.setNegativeButton(R.string.cancel, new Dialog.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Return the `DialogFragment` to the parent activity on cancel.
+ moveToFolderListener.onCancelMoveToFolder(MoveToFolder.this);
+ }
+ });
+
+ // Set the `onClick()` listener fo the positive button.
+ dialogBuilder.setPositiveButton(R.string.move, new Dialog.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // Return the `DialogFragment` to the parent activity on save.
+ moveToFolderListener.onMoveToFolder(MoveToFolder.this);
+ }
+ });
+
+ // Create an `AlertDialog` from the `AlertDialog.Builder`.
+ final AlertDialog alertDialog = dialogBuilder.create();
+
+ // We need to show the `AlertDialog` before we can modify items in the layout.
+ alertDialog.show();
+
+ // Initialize the `Cursor` and `CursorAdapter` variables.
+ Cursor foldersCursor;
+ CursorAdapter foldersCursorAdapter;
+
+ // Check to see if we are in the `Home Folder`.
+ if (BookmarksActivity.currentFolder.isEmpty()) { // Don't display `Home Folder` at the top of the `ListView`.
+ // Initialize `exceptFolders`.
+ exceptFolders = "";
+
+ // If a folder is selected, add it and all children to the list of folders not to display.
+ long[] selectedBookmarksLongArray = BookmarksActivity.bookmarksListView.getCheckedItemIds();
+ for (long databaseIdLong : selectedBookmarksLongArray) {
+ // Get `databaseIdInt` for each selected bookmark.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // If `databaseIdInt` is a folder.
+ if (BookmarksActivity.bookmarksDatabaseHandler.isFolder(databaseIdInt)) {
+ // Get the name of the selected folder.
+ String folderName = BookmarksActivity.bookmarksDatabaseHandler.getFolderName(databaseIdInt);
+
+ if (exceptFolders.isEmpty()){
+ // Add the selected folder to the list of folders not to display.
+ exceptFolders = DatabaseUtils.sqlEscapeString(folderName);
+ } else {
+ // Add the selected folder to the end of the list of folders not to display.
+ exceptFolders = exceptFolders + "," + DatabaseUtils.sqlEscapeString(folderName);
+ }
+
+ // Add the selected folder's subfolders to the list of folders not to display.
+ addSubfoldersToExceptFolders(folderName);
+ }
+ }
+
+ // Get a `Cursor` containing the folders to display.
+ foldersCursor = BookmarksActivity.bookmarksDatabaseHandler.getFoldersCursorExcept(exceptFolders);
+
+ // 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) {
+ // 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);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ // Get the folder icon from `cursor`.
+ byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHandler.FAVORITE_ICON));
+ // Convert the byte array to a `Bitmap` beginning at the first byte and ending at the last.
+ Bitmap folderIconBitmap = BitmapFactory.decodeByteArray(folderIconByteArray, 0, folderIconByteArray.length);
+ // Display `folderIconBitmap` in `move_to_folder_icon`.
+ ImageView folderIconImageView = (ImageView) view.findViewById(R.id.move_to_folder_icon);
+ assert folderIconImageView != null; // Remove the warning below that `currentIconImageView` might be null;
+ folderIconImageView.setImageBitmap(folderIconBitmap);
+
+ // Get the folder name from `cursor` and display it in `move_to_folder_name_textview`.
+ String folderName = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHandler.BOOKMARK_NAME));
+ TextView folderNameTextView = (TextView) view.findViewById(R.id.move_to_folder_name_textview);
+ folderNameTextView.setText(folderName);
+ }
+ };
+ } else { // Display `Home Folder` at the top of the `ListView`.
+ // Get the home folder icon drawable and convert it to a `Bitmap`. `this` specifies the current context.
+ Drawable homeFolderIconDrawable = ContextCompat.getDrawable(getActivity().getApplicationContext(), R.drawable.folder_grey_bitmap);
+ BitmapDrawable homeFolderIconBitmapDrawable = (BitmapDrawable) homeFolderIconDrawable;
+ Bitmap homeFolderIconBitmap = homeFolderIconBitmapDrawable.getBitmap();
+ // Convert the folder `Bitmap` to a byte array. `0` is for lossless compression (the only option for a PNG).
+ ByteArrayOutputStream homeFolderIconByteArrayOutputStream = new ByteArrayOutputStream();
+ homeFolderIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, homeFolderIconByteArrayOutputStream);
+ byte[] homeFolderIconByteArray = homeFolderIconByteArrayOutputStream.toByteArray();
+
+ // Setup a `MatrixCursor` for the `Home Folder`.
+ String[] homeFolderMatrixCursorColumnNames = {BookmarksDatabaseHandler._ID, BookmarksDatabaseHandler.BOOKMARK_NAME, BookmarksDatabaseHandler.FAVORITE_ICON};
+ MatrixCursor homeFolderMatrixCursor = new MatrixCursor(homeFolderMatrixCursorColumnNames);
+ homeFolderMatrixCursor.addRow(new Object[]{0, getString(R.string.home_folder), homeFolderIconByteArray});
+
+ // Add the parent folder to the list of folders not to display.
+ exceptFolders = DatabaseUtils.sqlEscapeString(BookmarksActivity.currentFolder);
+
+ // If a folder is selected, add it and all children to the list of folders not to display.
+ long[] selectedBookmarksLongArray = BookmarksActivity.bookmarksListView.getCheckedItemIds();
+ for (long databaseIdLong : selectedBookmarksLongArray) {
+ // Get `databaseIdInt` for each selected bookmark.
+ int databaseIdInt = (int) databaseIdLong;
+
+ // If `databaseIdInt` is a folder.
+ if (BookmarksActivity.bookmarksDatabaseHandler.isFolder(databaseIdInt)) {
+ // Get the name of the selected folder.
+ String folderName = BookmarksActivity.bookmarksDatabaseHandler.getFolderName(databaseIdInt);
+
+ // Add the selected folder to the end of the list of folders not to display.
+ exceptFolders = exceptFolders + "," + DatabaseUtils.sqlEscapeString(folderName);
+
+ // Add the selected folder's subfolders to the list of folders not to display.
+ addSubfoldersToExceptFolders(folderName);
+ }
+ }
+
+ // Get a `foldersCursor`.
+ foldersCursor = BookmarksActivity.bookmarksDatabaseHandler.getFoldersCursorExcept(exceptFolders);
+
+ // Combine `homeFolderMatrixCursor` and `foldersCursor`.
+ MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{homeFolderMatrixCursor, foldersCursor});
+
+ // Setup `foldersCursorAdaptor` with `this` context. `false` disables autoRequery.
+ foldersCursorAdapter = new CursorAdapter(alertDialog.getContext(), foldersMergeCursor, false) {
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ // 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);
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ // Get the folder icon from `cursor`.
+ byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHandler.FAVORITE_ICON));
+ // Convert the byte array to a `Bitmap` beginning at the first byte and ending at the last.
+ Bitmap folderIconBitmap = BitmapFactory.decodeByteArray(folderIconByteArray, 0, folderIconByteArray.length);
+ // Display `folderIconBitmap` in `move_to_folder_icon`.
+ ImageView folderIconImageView = (ImageView) view.findViewById(R.id.move_to_folder_icon);
+ assert folderIconImageView != null; // Remove the warning below that `currentIconImageView` might be null;
+ folderIconImageView.setImageBitmap(folderIconBitmap);
+
+ // Get the folder name from `cursor` and display it in `move_to_folder_name_textview`.
+ String folderName = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHandler.BOOKMARK_NAME));
+ TextView folderNameTextView = (TextView) view.findViewById(R.id.move_to_folder_name_textview);
+ folderNameTextView.setText(folderName);
+ }
+ };
+ }
+
+ // Display the ListView
+ ListView foldersListView = (ListView) alertDialog.findViewById(R.id.move_to_folder_listview);
+ assert foldersListView != null; // Remove the warning below that `foldersListView` might be null.
+ foldersListView.setAdapter(foldersCursorAdapter);
+
+ // `onCreateDialog` requires the return of an `AlertDialog`.
+ return alertDialog;
+ }
+
+ public void addSubfoldersToExceptFolders(String folderName) {
+ // Get a `Cursor` will all the immediate subfolders.
+ Cursor subfoldersCursor = BookmarksActivity.bookmarksDatabaseHandler.getSubfoldersCursor(folderName);
+
+ for (int i = 0; i < subfoldersCursor.getCount(); i++) {
+ // Move `subfolderCursor` to the current item.
+ subfoldersCursor.moveToPosition(i);
+
+ // Get the name of the subfolder.
+ String subfolderName = subfoldersCursor.getString(subfoldersCursor.getColumnIndex(BookmarksDatabaseHandler.BOOKMARK_NAME));
+
+ // Run the same tasks for any subfolders of the subfolder.
+ addSubfoldersToExceptFolders(subfolderName);
+
+ // Add the subfolder to `exceptFolders`.
+ subfolderName = DatabaseUtils.sqlEscapeString(subfolderName);
+ exceptFolders = exceptFolders + "," + subfolderName;
+ }
+
+ }
}
--- /dev/null
+<!-- folder_dark_blue.xml.xml comes from the Android Material icon set, where it is called ic_folder.
+ It is released under the CC-BY license <https://creativecommons.org/licenses/by/4.0/>. -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0" >
+
+ <path
+ android:fillColor="#FF0D47A1"
+ android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
+</vector>
+++ /dev/null
-<!-- folder.xml comes from the Android Material icon set, where it is called ic_folder.
- It is released under the CC-BY license <https://creativecommons.org/licenses/by/4.0/>. -->
-
-<vector
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:height="24dp"
- android:width="24dp"
- android:viewportHeight="24.0"
- android:viewportWidth="24.0" >
-
- <path
- android:fillColor="#FF9E9E9E"
- android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
-</vector>
--- /dev/null
+<!-- folder_grey.xml comes from the Android Material icon set, where it is called ic_folder.
+ It is released under the CC-BY license <https://creativecommons.org/licenses/by/4.0/>. -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0" >
+
+ <path
+ android:fillColor="#FF9E9E9E"
+ android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z"/>
+</vector>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser 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.
+
+ Privacy Browser 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 Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ android:id="@+id/bookmarks_database_view_item_linearlayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="vertical" >
+
+ <!-- First row. -->
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_marginTop="10dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/bookmarks_database_view_database_id"
+ android:layout_height="wrap_content"
+ android:layout_width="50dp"
+ android:layout_marginEnd="10dp"
+ android:gravity="end"
+ android:textColor="@color/grey"
+ android:textSize="22sp" />
+
+ <ImageView
+ android:id="@+id/bookmarks_database_view_favorite_icon"
+ android:layout_width="30dp"
+ android:layout_height="30dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="10dp"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ android:id='@+id/bookmarks_database_view_bookmark_name'
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="@color/black"
+ android:textSize="22sp"
+ android:singleLine="true" />
+ </LinearLayout>
+
+ <!-- Second row. -->
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="10dp"
+ android:orientation="horizontal" >
+
+ <TextView
+ android:id="@+id/bookmarks_database_view_display_order"
+ android:layout_height="wrap_content"
+ android:layout_width="50dp"
+ android:layout_marginEnd="10dp"
+ android:gravity="end"
+ android:textColor="@color/black"
+ android:textSize="22sp" />
+
+ <ImageView
+ android:id="@+id/bookmarks_database_view_parent_folder_icon"
+ android:layout_height="30dp"
+ android:layout_width="30dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginEnd="10dp"
+ android:src="@drawable/folder_grey"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ android:id="@+id/bookmarks_database_view_parent_folder"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="@color/black"
+ android:textSize="22sp"
+ android:textStyle="italic"
+ android:singleLine="true" />
+ </LinearLayout>
+
+ <!-- Third row. -->
+ <TextView
+ android:id="@+id/bookmarks_database_view_bookmark_url"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginBottom="10dp"
+ android:layout_marginStart="13dp"
+ android:layout_marginEnd="10dp"
+ android:textColor="@color/black"
+ android:textSize="22sp"
+ android:singleLine="true" />
+</LinearLayout>
\ No newline at end of file
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright 2016 Soren Stoutner <soren@stoutner.com>.
-
- This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
-
- Privacy Browser 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.
-
- Privacy Browser 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 Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
-
-<LinearLayout
- android:id="@+id/bookmarks_database_view_item_linearlayout"
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:orientation="vertical" >
-
- <!-- First row. -->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- android:layout_marginTop="10dp"
- android:layout_marginStart="10dp"
- android:layout_marginEnd="10dp"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/bookmarks_database_view_database_id"
- android:layout_height="wrap_content"
- android:layout_width="50dp"
- android:layout_marginEnd="10dp"
- android:gravity="end"
- android:textColor="@color/grey"
- android:textSize="22sp" />
-
- <ImageView
- android:id="@+id/bookmarks_database_view_favorite_icon"
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="10dp"
- tools:ignore="ContentDescription" />
-
- <TextView
- android:id='@+id/bookmarks_database_view_bookmark_name'
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textColor="@color/black"
- android:textSize="22sp"
- android:singleLine="true" />
- </LinearLayout>
-
- <!-- Second row. -->
- <LinearLayout
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginStart="10dp"
- android:layout_marginEnd="10dp"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/bookmarks_database_view_display_order"
- android:layout_height="wrap_content"
- android:layout_width="50dp"
- android:layout_marginEnd="10dp"
- android:gravity="end"
- android:textColor="@color/black"
- android:textSize="22sp" />
-
- <ImageView
- android:layout_height="30dp"
- android:layout_width="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="10dp"
- android:src="@drawable/folder"
- tools:ignore="ContentDescription" />
-
- <TextView
- android:id="@+id/bookmarks_database_view_parent_folder"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textColor="@color/black"
- android:textSize="22sp"
- android:textStyle="italic"
- android:singleLine="true" />
- </LinearLayout>
-
- <!-- Third row. -->
- <TextView
- android:id="@+id/bookmarks_database_view_bookmark_url"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:layout_marginBottom="10dp"
- android:layout_marginStart="13dp"
- android:layout_marginEnd="10dp"
- android:textColor="@color/black"
- android:textSize="22sp"
- android:singleLine="true" />
-</LinearLayout>
\ No newline at end of file
android:layout_gravity="start"
app:headerLayout="@layout/navigation_header"
app:menu="@menu/webview_navigation_menu"
- app:itemIconTint="@color/blue_gray" />
+ app:itemIconTint="@color/blue_grey" />
<!-- fullScreenVideoFrameLayout is used to display full screen videos. It is initially android:visibility="gone" to hide it from view. -->
<FrameLayout
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser 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.
+
+ Privacy Browser 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 Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<!-- `android:dividerHeight` must be specified with `android:divider` or the height will be `0dp`.
+ In our case we want the height to be `0dp`. -->
+<ListView
+ android:id="@+id/move_to_folder_listview"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:choiceMode="singleChoice"
+ android:divider="@color/white"
+ android:dividerHeight="0dp" />
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright 2016 Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser 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.
+
+ Privacy Browser 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 Privacy Browser. If not, see <http://www.gnu.org/licenses/>. -->
+
+<LinearLayout
+ android:id="@+id/move_to_folder_item_linearlayout"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:orientation="horizontal"
+ android:background="@drawable/bookmarks_list_selector" >
+
+ <ImageView
+ android:id="@+id/move_to_folder_icon"
+ android:layout_height="30dp"
+ android:layout_width="30dp"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="10dp"
+ tools:ignore="ContentDescription" />
+
+ <TextView
+ android:id="@+id/move_to_folder_name_textview"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_margin="10dp"
+ android:singleLine="true"
+ android:textColor="@color/black"
+ android:textSize="22sp" />
+</LinearLayout>
\ No newline at end of file
<color name="black">#FF000000</color>
<color name="blue">#FF1976D2</color>
<color name="dark_blue">#FF0D47A1</color>
- <color name="blue_gray">#FF607D8B</color>
+ <color name="blue_grey">#FF607D8B</color>
<color name="grey">#FF9E9E9E</color>
<color name="green">#FF64DD17</color>
<color name="light_blue">#FFBBDEFB</color>
<string name="folder_names_must_be_unique">Folder names must be unique</string>
<string name="cannot_create_folder">Cannot create the folder because the name is not unique:</string>
<string name="cannot_rename_folder">Cannot rename the folder because the new name is not unique:</string>
+ <string name="cannot_move_bookmarks">Cannot move the selected bookmarks because no new folder was selected.</string>
<string name="edit_bookmark">Edit bookmark</string>
<string name="edit_folder">Edit folder</string>
<string name="move_to_folder">Move to Folder</string>
+ <string name="move">Move</string>
<string name="save">Save</string>
<string name="bookmark_name">Bookmark name</string>
<string name="bookmark_url">Bookmark URL</string>
<!-- Bookmarks Database View. -->
<string name="bookmarks_database_view">Bookmarks Database View</string>
- <string name="home_folder">Home folder</string>
+ <string name="home_folder">Home Folder</string>
<!-- Guide. -->
<string name="privacy_browser_guide">Privacy Browser Guide</string>