From e12908eb00d9c54c0a3c9f56312a31b9e5dfd094 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Tue, 24 Oct 2017 13:15:58 -0700 Subject: [PATCH] Use a spinner to select folders in the bookmarks database view. https://redmine.stoutner.com/issues/50 --- .../activities/BookmarksActivity.java | 8 +- .../BookmarksDatabaseViewActivity.java | 113 ++++++++++++++++-- .../dialogs/MoveToFolderDialog.java | 4 +- .../fragments/DomainSettingsFragment.java | 20 ++-- .../helpers/BookmarksDatabaseHelper.java | 19 ++- .../bookmarks_spinner_color_selector_dark.xml | 25 ++++ ...bookmarks_spinner_color_selector_light.xml | 25 ++++ ...kmarks_databaseview_coordinatorlayout.xml} | 2 +- ...kmarks_databaseview_item_linearlayout.xml} | 2 + .../layout/bookmarks_databaseview_spinner.xml | 25 ++++ ...rks_databaseview_spinner_dropdown_item.xml | 35 ++++++ .../bookmarks_databaseview_spinner_item.xml | 31 +++++ ...domain_settings_spinner_dropdown_item.xml} | 2 +- ...m.xml => domain_settings_spinner_item.xml} | 2 +- app/src/main/res/values/attrs.xml | 3 + app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 6 + 18 files changed, 296 insertions(+), 29 deletions(-) create mode 100644 app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml create mode 100644 app/src/main/res/color/bookmarks_spinner_color_selector_light.xml rename app/src/main/res/layout/{bookmarks_database_view_coordinatorlayout.xml => bookmarks_databaseview_coordinatorlayout.xml} (93%) rename app/src/main/res/layout/{bookmarks_database_view_item_linearlayout.xml => bookmarks_databaseview_item_linearlayout.xml} (97%) create mode 100644 app/src/main/res/layout/bookmarks_databaseview_spinner.xml create mode 100644 app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml create mode 100644 app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml rename app/src/main/res/layout/{spinner_dropdown_item.xml => domain_settings_spinner_dropdown_item.xml} (96%) rename app/src/main/res/layout/{spinner_item.xml => domain_settings_spinner_item.xml} (91%) 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 42b1c0e1..e640b792 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -116,8 +116,12 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Get the intent that launched the activity. Intent launchingIntent = getIntent(); - // Get the current folder from the `Intent`. - currentFolder = launchingIntent.getStringExtra("Current Folder"); + // Set the current folder variable. + if (launchingIntent.getStringExtra("Current Folder") != null) { // Set the current folder from the intent. + currentFolder = launchingIntent.getStringExtra("Current Folder"); + } else { // Set the current folder to be `""`, which is the home folder. + currentFolder = ""; + } // Set the content view. setContentView(R.layout.bookmarks_coordinatorlayout); 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 53fb657d..1725cac4 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java @@ -21,19 +21,24 @@ package com.stoutner.privacybrowser.activities; import android.content.Context; import android.database.Cursor; +import android.database.MatrixCursor; +import android.database.MergeCursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Typeface; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.support.v4.widget.CursorAdapter; +import android.support.v4.widget.ResourceCursorAdapter; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListView; +import android.widget.Spinner; import android.widget.TextView; import com.stoutner.privacybrowser.R; @@ -46,6 +51,9 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity { // `bookmarksListView` is used in `onCreate()` and `updateBookmarksListView()`. private ListView bookmarksListView; + // `bookmarksCursorAdapter` is used in `onCreate()` and `updateBookmarksListView()`. + private CursorAdapter bookmarksCursorAdapter; + @Override public void onCreate(Bundle savedInstanceState) { // Set the activity theme. @@ -56,26 +64,109 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity { } super.onCreate(savedInstanceState); - setContentView(R.layout.bookmarks_database_view_coordinatorlayout); + setContentView(R.layout.bookmarks_databaseview_coordinatorlayout); // We need to use the `SupportActionBar` from `android.support.v7.app.ActionBar` until the minimum API is >= 21. final Toolbar bookmarksDatabaseViewAppBar = (Toolbar) findViewById(R.id.bookmarks_database_view_toolbar); setSupportActionBar(bookmarksDatabaseViewAppBar); - // Display the home arrow on `SupportActionBar`. + // Get a handle for the `AppBar`. final ActionBar appBar = getSupportActionBar(); - assert appBar != null; // This assert removes the incorrect warning in Android Studio on the following line that appBar might be null. - appBar.setDisplayHomeAsUpEnabled(true); - // Initialize the database handler and the ListView. - // `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`. + // Remove the incorrect warning in Android Studio that `appBar` might be null. + assert appBar != null; + + // Display the `Spinner` and the back arrow in the `AppBar`. + appBar.setCustomView(R.layout.bookmarks_databaseview_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`. bookmarksDatabaseHelper = new BookmarksDatabaseHelper(this, null, null, 0); + + // Setup a `MatrixCursor` for "All Folders" and "Home Folder". + String[] matrixCursorColumnNames = {BookmarksDatabaseHelper._ID, BookmarksDatabaseHelper.BOOKMARK_NAME}; + MatrixCursor matrixCursor = new MatrixCursor(matrixCursorColumnNames); + matrixCursor.addRow(new Object[]{-2, getString(R.string.all_folders)}); + matrixCursor.addRow(new Object[]{-1, getString(R.string.home_folder)}); + + // Get a `Cursor` with the list of all the folders. + Cursor foldersCursor = bookmarksDatabaseHelper.getAllFoldersCursor(); + + // Combine `matrixCursor` and `foldersCursor`. + MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); + + // Create a `ResourceCursorAdapter` for the spinner with `this` context. `0` specifies no flags.; + ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(this, R.layout.bookmarks_databaseview_spinner_item, foldersMergeCursor, 0) { + @Override + public void bindView(View view, Context context, Cursor cursor) { + // Get a handle for the spinner item `TextView`. + TextView spinnerItemTextView = (TextView) view.findViewById(R.id.spinner_item_textview); + + // Set the `TextView` to display the folder name. + spinnerItemTextView.setText(cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); + } + }; + + // Set the `ResourceCursorAdapter` drop drown view resource. + foldersCursorAdapter.setDropDownViewResource(R.layout.bookmarks_databaseview_spinner_dropdown_item); + + // Get a handle for the folder `Spinner`. + Spinner folderSpinner = (Spinner) findViewById(R.id.bookmarks_database_view_spinner); + + // Set the adapter for the folder `Spinner`. + folderSpinner.setAdapter(foldersCursorAdapter); + + // Handle clicks on the `Spinner` dropdown. + folderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + // Convert the database ID to an `int`. + int databaseId = (int) id; + + // Instantiate the bookmarks `Cursor`. + Cursor bookmarksCursor; + + // Populate the bookmarks `ListView` based on the `Spinner` selection. + switch (databaseId) { + // Display all the folders. + case -2: + // Get a cursor with all the folders. + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(); + break; + + // Display the home folder. + case -1: + // Get a cursor for the home folder. + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(""); + break; + + // Display the selected folder. + default: + // Get a handle for the selected view. + TextView selectedFolderTextView = (TextView) view.findViewById(R.id.spinner_item_textview); + + // Extract the name of the selected folder. + String folderName = selectedFolderTextView.getText().toString(); + + // Get a cursor for the selected folder. + bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(folderName); + } + + // Update the `ListView`. + bookmarksCursorAdapter.changeCursor(bookmarksCursor); + } + + @Override + public void onNothingSelected(AdapterView parent) { + // Do nothing. + } + }); + + // Get a handle for the bookmarks `ListView`. bookmarksListView = (ListView) findViewById(R.id.bookmarks_database_view_listview); - // Display the bookmarks in the ListView. + // Display the bookmarks in the `ListView`. updateBookmarksListView(); - } private void updateBookmarksListView() { @@ -83,11 +174,11 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity { final Cursor bookmarksCursor = bookmarksDatabaseHelper.getAllBookmarksCursor(); // Setup `bookmarksCursorAdapter` with `this` context. The `false` disables autoRequery. - CursorAdapter bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, false) { + bookmarksCursorAdapter = new CursorAdapter(this, bookmarksCursor, 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 getLayoutInflater().inflate(R.layout.bookmarks_database_view_item_linearlayout, parent, false); + return getLayoutInflater().inflate(R.layout.bookmarks_databaseview_item_linearlayout, parent, false); } @Override 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 8ced87d3..eff2f777 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/MoveToFolderDialog.java @@ -223,13 +223,13 @@ public class MoveToFolderDialog extends AppCompatDialogFragment { } } - // Get a `foldersCursor`. + // Get a `Cursor` containing the folders to display. foldersCursor = BookmarksActivity.bookmarksDatabaseHelper.getFoldersCursorExcept(exceptFolders); // Combine `homeFolderMatrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{homeFolderMatrixCursor, foldersCursor}); - // Setup `foldersCursorAdaptor` with `this` context. `false` disables autoRequery. + // Setup `foldersCursorAdaptor`. `false` disables autoRequery. foldersCursorAdapter = new CursorAdapter(alertDialog.getContext(), foldersMergeCursor, false) { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { diff --git a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java index 31dd0278..0fd7a692 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java +++ b/app/src/main/java/com/stoutner/privacybrowser/fragments/DomainSettingsFragment.java @@ -192,18 +192,18 @@ public class DomainSettingsFragment extends Fragment { } // Create `ArrayAdapters` for the `Spinners`and their `entry values`. - ArrayAdapter userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.spinner_item); - final ArrayAdapter userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entry_values, R.layout.spinner_item); - ArrayAdapter fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.spinner_item); - ArrayAdapter fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.spinner_item); - final ArrayAdapter displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.spinner_item); - ArrayAdapter nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.spinner_item); + ArrayAdapter userAgentArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entries, R.layout.domain_settings_spinner_item); + final ArrayAdapter userAgentEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_user_agent_entry_values, R.layout.domain_settings_spinner_item); + ArrayAdapter fontSizeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entries, R.layout.domain_settings_spinner_item); + ArrayAdapter fontSizeEntryValuesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.domain_settings_font_size_entry_values, R.layout.domain_settings_spinner_item); + final ArrayAdapter displayImagesArrayAdapter = ArrayAdapter.createFromResource(context, R.array.display_webpage_images_array, R.layout.domain_settings_spinner_item); + ArrayAdapter nightModeArrayAdapter = ArrayAdapter.createFromResource(context, R.array.night_mode_array, R.layout.domain_settings_spinner_item); // Set the `DropDownViewResource` on the `Spinners`. - userAgentArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); - fontSizeArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); - displayImagesArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); - nightModeArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item); + userAgentArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item); + fontSizeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item); + displayImagesArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item); + nightModeArrayAdapter.setDropDownViewResource(R.layout.domain_settings_spinner_dropdown_item); // Set the `ArrayAdapters` for the `Spinners`. userAgentSpinner.setAdapter(userAgentArrayAdapter); 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 84481518..532c771d 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java @@ -231,7 +231,8 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { // Prepare the SQL statement to get the `Cursor` for all the folders. final String GET_ALL_FOLDERS = "SELECT * FROM " + BOOKMARKS_TABLE + - " WHERE " + IS_FOLDER + " = " + 1; + " WHERE " + IS_FOLDER + " = " + 1 + + " 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. @@ -251,6 +252,22 @@ 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 readable database handle. + SQLiteDatabase bookmarksDatabase = this.getReadableDatabase(); + + // SQL escape `folderName`. + folderName = DatabaseUtils.sqlEscapeString(folderName); + + // Get everything in the `BOOKMARKS_TABLE` with `folderName` as the `PARENT_FOLDER`. + final String GET_ALL_BOOKMARKS = "SELECT * FROM " + BOOKMARKS_TABLE + + " WHERE " + PARENT_FOLDER + " = " + folderName; + + // 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, null); + } + // Get a `Cursor` for all bookmarks and folders in the specified folder ordered by display order. public Cursor getAllBookmarksCursorByDisplayOrder(String folderName) { // Get a readable database handle. diff --git a/app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml b/app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml new file mode 100644 index 00000000..dae2ca44 --- /dev/null +++ b/app/src/main/res/color/bookmarks_spinner_color_selector_dark.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/bookmarks_spinner_color_selector_light.xml b/app/src/main/res/color/bookmarks_spinner_color_selector_light.xml new file mode 100644 index 00000000..3e8f830e --- /dev/null +++ b/app/src/main/res/color/bookmarks_spinner_color_selector_light.xml @@ -0,0 +1,25 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bookmarks_database_view_coordinatorlayout.xml b/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml similarity index 93% rename from app/src/main/res/layout/bookmarks_database_view_coordinatorlayout.xml rename to app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml index d81c02d3..207b19d9 100644 --- a/app/src/main/res/layout/bookmarks_database_view_coordinatorlayout.xml +++ b/app/src/main/res/layout/bookmarks_databaseview_coordinatorlayout.xml @@ -28,7 +28,7 @@ android:layout_width="match_parent" android:fitsSystemWindows="true" > - + @@ -93,6 +94,7 @@ android:layout_width="wrap_content" android:textSize="22sp" android:textStyle="italic" + android:ellipsize="end" android:maxLines="1" /> diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner.xml new file mode 100644 index 00000000..804ac3ac --- /dev/null +++ b/app/src/main/res/layout/bookmarks_databaseview_spinner.xml @@ -0,0 +1,25 @@ + + + + + diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml new file mode 100644 index 00000000..8df232bc --- /dev/null +++ b/app/src/main/res/layout/bookmarks_databaseview_spinner_dropdown_item.xml @@ -0,0 +1,35 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml b/app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml new file mode 100644 index 00000000..62cbb1d0 --- /dev/null +++ b/app/src/main/res/layout/bookmarks_databaseview_spinner_item.xml @@ -0,0 +1,31 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/spinner_dropdown_item.xml b/app/src/main/res/layout/domain_settings_spinner_dropdown_item.xml similarity index 96% rename from app/src/main/res/layout/spinner_dropdown_item.xml rename to app/src/main/res/layout/domain_settings_spinner_dropdown_item.xml index f62fa718..bef27af6 100644 --- a/app/src/main/res/layout/spinner_dropdown_item.xml +++ b/app/src/main/res/layout/domain_settings_spinner_dropdown_item.xml @@ -20,7 +20,7 @@ + + + diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 821407a6..94c863b8 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -33,7 +33,9 @@ #FF1E88E5 #FF1976D2 #881976D2 + #FF1770C6 #FF1565C0 + #FF1760B5 #FF0D47A1 #FF082B61 #FF2962FF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 42310bb4..256bddbe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -195,6 +195,7 @@ Bookmarks Database View + All Folders Home Folder diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1f180735..8b5027a6 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -46,6 +46,9 @@ @color/blue_200 @color/blue_700 @color/primary_text_color_selector_light + @color/white + @color/bookmarks_spinner_color_selector_light + @color/blue_750 @drawable/list_selector_light @color/blue_900 @color/blue_700 @@ -127,6 +130,9 @@ @color/blue_800 @color/blue_800 @color/primary_text_color_selector_dark + @color/gray_300 + @color/bookmarks_spinner_color_selector_dark + @color/blue_830 @color/blue_600 @color/blue_400 @color/gray_850 -- 2.43.0