From 81931a2a88e383f1071ab5134afe5bd70b31895d Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Tue, 12 Jul 2016 21:22:49 -0700 Subject: [PATCH] Add the ability to reorder bookmarks. --- app/src/main/assets/about_licenses.html | 4 + .../images/ic_vertical_align_bottom.png | Bin 0 -> 554 bytes .../assets/images/ic_vertical_align_top.png | Bin 0 -> 558 bytes .../privacybrowser/BookmarksActivity.java | 171 ++++++++++++++++-- .../BookmarksDatabaseHandler.java | 25 ++- .../drawable/move_bookmark_down_disabled.xml | 15 ++ .../drawable/move_bookmark_down_enabled.xml | 14 ++ .../drawable/move_bookmark_up_disabled.xml | 15 ++ .../res/drawable/move_bookmark_up_enabled.xml | 14 ++ .../main/res/menu/bookmarks_context_menu.xml | 20 +- app/src/main/res/values/strings.xml | 2 + 11 files changed, 256 insertions(+), 24 deletions(-) create mode 100644 app/src/main/assets/images/ic_vertical_align_bottom.png create mode 100644 app/src/main/assets/images/ic_vertical_align_top.png create mode 100644 app/src/main/res/drawable/move_bookmark_down_disabled.xml create mode 100644 app/src/main/res/drawable/move_bookmark_down_enabled.xml create mode 100644 app/src/main/res/drawable/move_bookmark_up_disabled.xml create mode 100644 app/src/main/res/drawable/move_bookmark_up_enabled.xml diff --git a/app/src/main/assets/about_licenses.html b/app/src/main/assets/about_licenses.html index bb6fa1a2..63e79966 100644 --- a/app/src/main/assets/about_licenses.html +++ b/app/src/main/assets/about_licenses.html @@ -77,6 +77,10 @@

ic_add.

+

ic_vertical_align_top

+ +

ic_vertical_align_bottom

+

ic_edit.

ic_download.

diff --git a/app/src/main/assets/images/ic_vertical_align_bottom.png b/app/src/main/assets/images/ic_vertical_align_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..620a1201442f8a3597ccaff49af50f067e5c7162 GIT binary patch literal 554 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSEX7WqAsj$Z!;#Vf4nJ zsJsMW#sHP)KY)UgC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NHH)lF86eC z45^s&_U>Na!wd{97nuW%8KW<>IBw!--XO-~)XT!{;FvK%K<&r>dy{p{Cq90$PpfMV z3(#~BNZ8%yd5>N0c&j~xv}zY-%pbs{{LtC{o|}B1~-?hpR7_g_}6nytns7xhG`r<`xh()^0{k9AJQgaEXVF|`0tkRN7lle>GAs$@jzXC zyuAm0SbvLVIi~+17)X4wWqK_BtLwmzqwkFVv@Ze&mbB^B&y4RL|Ngqs_UY%J9E*2J z{ccikS2^Cf?revR(y}=Wr#Kg&5@2nhU{1GV;56J_?RodA7)Z?1)z4*}Q$iB}ggwZ^ literal 0 HcmV?d00001 diff --git a/app/src/main/assets/images/ic_vertical_align_top.png b/app/src/main/assets/images/ic_vertical_align_top.png new file mode 100644 index 0000000000000000000000000000000000000000..607c9e6a81da03e06b4f7683615c2904f461f8b5 GIT binary patch literal 558 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSEX7WqAsj$Z!;#Vf4nJ zsJsMW#sHP)KY)UgC9V-A!TD(=<%vb94CUqJdYO6I#mR{Use1WE>9gP2NHH)luJ&|s z45^s&_Rel!I@awH9>yPHWM-!_gYR(d(diM7z?JuhX}oMMC=g=XuJ1i_GMH z*PV0o1KI!vZIwQsp2d8znYZPD!~SDCG+rw<6ftS2qY~e%m%O&?FS(nxFBqh$Ve=h1 zzSg|SZzk_i+d2DZ+>9HAe;zAeSJL=YStBU&GYd%k$g2^|xpCp6>juZ=efmwjmgPYH z0srIT2fJc{@@p!>23(ehdRgKmwV8VT0lO3@w3um8r7dK|-FcelF{r5}E+0g3_b_ literal 0 HcmV?d00001 diff --git a/app/src/main/java/com/stoutner/privacybrowser/BookmarksActivity.java b/app/src/main/java/com/stoutner/privacybrowser/BookmarksActivity.java index b6e67c89..75a34021 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/BookmarksActivity.java @@ -35,6 +35,7 @@ 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.util.SparseBooleanArray; import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; @@ -62,6 +63,9 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // `contextualActionMode` is used in `onCreate()` and `onEditBookmarkSave()`. private ActionMode contextualActionMode; + // `selectedBookmarkPosition` is used in `onCreate()` and `onEditBookarkSave()`. + private int selectedBookmarkPosition; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -105,11 +109,17 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // `MultiChoiceModeListener` handles long clicks. bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { + // `moveBookmarkUpMenuItem` is used in `onCreateActionMode()` and `onItemCheckedStateChanged`. + MenuItem moveBookmarkUpMenuItem; + + // `moveBookmarkDownMenuItem` is used in `onCreateActionMode()` and `onItemCheckedStateChanged`. + MenuItem moveBookmarkDownMenuItem; + // `editBookmarkMenuItem` is used in `onCreateActionMode()` and `onItemCheckedStateChanged`. MenuItem editBookmarkMenuItem; // `selectAllBookmarks` is used in `onCreateActionMode()` and `onItemCheckedStateChanges`. - MenuItem selectAllBookmarks; + MenuItem selectAllBookmarksMenuItem; @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { @@ -117,9 +127,11 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma getMenuInflater().inflate(R.menu.bookmarks_context_menu, menu); mode.setTitle(R.string.bookmarks); - // Get a handle for `R.id.edit_bookmark` and `R.id.select_all_bookmarks`. + // Get a handle for MenuItems we need to selectively disable. + moveBookmarkUpMenuItem = menu.findItem(R.id.move_bookmark_up); + moveBookmarkDownMenuItem = menu.findItem(R.id.move_bookmark_down); editBookmarkMenuItem = menu.findItem(R.id.edit_bookmark); - selectAllBookmarks = menu.findItem(R.id.context_menu_select_all_bookmarks); + selectAllBookmarksMenuItem = menu.findItem(R.id.context_menu_select_all_bookmarks); return true; } @@ -140,18 +152,46 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // List the number of selected bookmarks in the subtitle. mode.setSubtitle(numberOfSelectedBookmarks + " " + getString(R.string.selected)); - // Show the `Edit` option only if 1 bookmark is selected. - if (numberOfSelectedBookmarks < 2) { + if (numberOfSelectedBookmarks == 1) { + // Show the `Move Up`, `Move Down`, and `Edit` option only if 1 bookmark is selected. + moveBookmarkUpMenuItem.setVisible(true); + moveBookmarkDownMenuItem.setVisible(true); editBookmarkMenuItem.setVisible(true); - } else { + + // Get the database IDs for the bookmarks. + int selectedBookmarkDatabaseId = (int) selectedBookmarksLongArray[0]; + int firstBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(0); + // bookmarksListView is 0 indexed. + int lastBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(bookmarksListView.getCount() - 1); + + // Disable `moveBookmarkUpMenuItem` if the selected bookmark is at the top of the ListView. + if (selectedBookmarkDatabaseId == firstBookmarkDatabaseId) { + moveBookmarkUpMenuItem.setEnabled(false); + moveBookmarkUpMenuItem.setIcon(R.drawable.move_bookmark_up_disabled); + } else { // Otherwise enable `moveBookmarkUpMenuItem`. + moveBookmarkUpMenuItem.setEnabled(true); + moveBookmarkUpMenuItem.setIcon(R.drawable.move_bookmark_up_enabled); + } + + // Disable `moveBookmarkDownMenuItem` if the selected bookmark is at the bottom of the ListView. + if (selectedBookmarkDatabaseId == lastBookmarkDatabaseId) { + moveBookmarkDownMenuItem.setEnabled(false); + moveBookmarkDownMenuItem.setIcon(R.drawable.move_bookmark_down_disabled); + } else { // Otherwise enable `moveBookmarkDownMenuItem`. + moveBookmarkDownMenuItem.setEnabled(true); + moveBookmarkDownMenuItem.setIcon(R.drawable.move_bookmark_down_enabled); + } + } else { // Hide the MenuItems because more than one bookmark is selected. + moveBookmarkUpMenuItem.setVisible(false); + moveBookmarkDownMenuItem.setVisible(false); editBookmarkMenuItem.setVisible(false); } // Do not show `Select All` if all the bookmarks are already checked. if (bookmarksListView.getCheckedItemIds().length == bookmarksListView.getCount()) { - selectAllBookmarks.setVisible(false); + selectAllBookmarksMenuItem.setVisible(false); } else { - selectAllBookmarks.setVisible(true); + selectAllBookmarksMenuItem.setVisible(true); } } @@ -159,13 +199,101 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma public boolean onActionItemClicked(ActionMode mode, MenuItem item) { int menuItemId = item.getItemId(); + // `numberOfBookmarks` is used in `R.id.move_bookmark_up_enabled`, `R.id.move_bookmark_down_enabled`, and `R.id.context_menu_select_all_bookmarks`. + int numberOfBookmarks; + + // `selectedBookmarkLongArray` is used in `R.id.move_bookmark_up` and `R.id.move_bookmark_down`. + long[]selectedBookmarkLongArray; + // `selectedBookmarkDatabaseId` is used in `R.id.move_bookmark_up` and `R.id.move_bookmark_down`. + int selectedBookmarkDatabaseId; + // `selectedBookmarkNewPosition` is used in `R.id.move_bookmark_up` and `R.id.move_bookmark_down`. + int selectedBookmarkNewPosition; + switch (menuItemId) { + case R.id.move_bookmark_up: + // Get the selected bookmark database ID. + selectedBookmarkLongArray = bookmarksListView.getCheckedItemIds(); + selectedBookmarkDatabaseId = (int) selectedBookmarkLongArray[0]; + + // Initialize `selectedBookmarkNewPosition`. + selectedBookmarkNewPosition = 0; + + for (int i = 0; i < bookmarksListView.getCount(); i++) { + int databaseId = (int) bookmarksListView.getItemIdAtPosition(i); + int nextBookmarkDatabaseId = (int) bookmarksListView.getItemIdAtPosition(i + 1); + + if (databaseId == selectedBookmarkDatabaseId || nextBookmarkDatabaseId == selectedBookmarkDatabaseId) { + if (databaseId == selectedBookmarkDatabaseId) { + // Move the selected bookmark up one and store the new bookmark position. + bookmarksDatabaseHandler.updateBookmarkDisplayOrder(databaseId, i - 1); + selectedBookmarkNewPosition = i - 1; + } else { // Move the bookmark above the selected bookmark down one. + bookmarksDatabaseHandler.updateBookmarkDisplayOrder(databaseId, i + 1); + } + } else { + // Reset the rest of the bookmarks' DISPLAY_ORDER to match the position in the ListView. + // This isn't necessary, but it clears out any stray values that might have crept into the database. + bookmarksDatabaseHandler.updateBookmarkDisplayOrder(databaseId, i); + } + } + + // Refresh the ListView. + updateBookmarksListView(); + + // Select the previously selected bookmark in the new location. + bookmarksListView.setItemChecked(selectedBookmarkNewPosition, true); + + bookmarksListView.setSelection(selectedBookmarkNewPosition - 5); + + break; + + case R.id.move_bookmark_down: + // Get the selected bookmark database ID. + selectedBookmarkLongArray = bookmarksListView.getCheckedItemIds(); + selectedBookmarkDatabaseId = (int) selectedBookmarkLongArray[0]; + + // Initialize `selectedBookmarkNewPosition`. + selectedBookmarkNewPosition = 0; + + for (int i = 0; i 1. } - public void createBookmark(String bookmarkName, String bookmarkURL, byte[] favoriteIcon) { + public void createBookmark(String bookmarkName, String bookmarkURL, int displayOrder, byte[] favoriteIcon) { ContentValues bookmarkContentValues = new ContentValues(); // ID is created automatically. + bookmarkContentValues.put(DISPLAY_ORDER, displayOrder); bookmarkContentValues.put(BOOKMARK_NAME, bookmarkName); bookmarkContentValues.put(BOOKMARK_URL, bookmarkURL); bookmarkContentValues.put(PARENT_FOLDER, ""); @@ -86,7 +87,7 @@ public class BookmarksDatabaseHandler extends SQLiteOpenHelper { // Get a readable database handle. SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); - // Prepare the SQL statement to get the cursor for `databaseId`. + // Prepare the SQL statement to get the cursor for `databaseId` final String GET_ONE_BOOKMARK = "Select * FROM " + BOOKMARKS_TABLE + " WHERE " + _ID + " = " + databaseId; @@ -113,7 +114,7 @@ public class BookmarksDatabaseHandler extends SQLiteOpenHelper { // 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 " + _ID + " NOT IN (" + doNotGetIdsString + ")"; + " WHERE " + _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. // We can't close the `Cursor` because we need to use it in the parent activity. @@ -125,7 +126,7 @@ public class BookmarksDatabaseHandler extends SQLiteOpenHelper { SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); // Get everything in the BOOKMARKS_TABLE. - final String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE; + final String GET_ALL_BOOKMARKS = "Select * FROM " + BOOKMARKS_TABLE + " 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. @@ -191,6 +192,22 @@ public class BookmarksDatabaseHandler extends SQLiteOpenHelper { bookmarksDatabase.close(); } + public void updateBookmarkDisplayOrder(int databaseId, int displayOrder) { + // Store the updated values in `bookmarkContentValues`. + ContentValues bookmarkContentValues = new ContentValues(); + + bookmarkContentValues.put(DISPLAY_ORDER, displayOrder); + + // Get a writable database handle. + SQLiteDatabase bookmarksDatabase = this.getWritableDatabase(); + + // 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 deleteBookmark(int databaseId) { // Get a writable database handle. SQLiteDatabase bookmarksDatabase = this.getWritableDatabase(); diff --git a/app/src/main/res/drawable/move_bookmark_down_disabled.xml b/app/src/main/res/drawable/move_bookmark_down_disabled.xml new file mode 100644 index 00000000..674fcda7 --- /dev/null +++ b/app/src/main/res/drawable/move_bookmark_down_disabled.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/app/src/main/res/drawable/move_bookmark_down_enabled.xml b/app/src/main/res/drawable/move_bookmark_down_enabled.xml new file mode 100644 index 00000000..90b5ae1b --- /dev/null +++ b/app/src/main/res/drawable/move_bookmark_down_enabled.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/drawable/move_bookmark_up_disabled.xml b/app/src/main/res/drawable/move_bookmark_up_disabled.xml new file mode 100644 index 00000000..c38ad46c --- /dev/null +++ b/app/src/main/res/drawable/move_bookmark_up_disabled.xml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/app/src/main/res/drawable/move_bookmark_up_enabled.xml b/app/src/main/res/drawable/move_bookmark_up_enabled.xml new file mode 100644 index 00000000..06c837d5 --- /dev/null +++ b/app/src/main/res/drawable/move_bookmark_up_enabled.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/app/src/main/res/menu/bookmarks_context_menu.xml b/app/src/main/res/menu/bookmarks_context_menu.xml index 98b790ad..ba1139ee 100644 --- a/app/src/main/res/menu/bookmarks_context_menu.xml +++ b/app/src/main/res/menu/bookmarks_context_menu.xml @@ -22,24 +22,38 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 69424458..a4a030e0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -80,6 +80,8 @@ Selected + Move Up + Move down Edit Delete Select All -- 2.43.0