From 47b689dbdaf08b9636021ddd8f72ca9ee7f11998 Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Mon, 21 Jan 2019 15:23:15 -0700 Subject: [PATCH] Display the folder icons in the spinners in the bookmarks database view activity. https://redmine.stoutner.com/issues/218 --- .idea/dictionaries/soren.xml | 7 + .../main/assets/de/about_licenses_dark.html | 8 ++ .../main/assets/de/about_licenses_light.html | 8 ++ .../main/assets/en/about_licenses_dark.html | 8 ++ .../main/assets/en/about_licenses_light.html | 8 ++ .../main/assets/es/about_licenses_dark.html | 8 ++ .../main/assets/es/about_licenses_light.html | 8 ++ .../main/assets/it/about_licenses_dark.html | 8 ++ .../main/assets/it/about_licenses_light.html | 8 ++ .../main/assets/ru/about_licenses_dark.html | 8 ++ .../main/assets/ru/about_licenses_light.html | 8 ++ .../main/assets/tr/about_licenses_dark.html | 8 ++ .../main/assets/tr/about_licenses_light.html | 8 ++ .../activities/BookmarksActivity.java | 7 +- .../BookmarksDatabaseViewActivity.java | 52 +++++++- .../dialogs/CreateBookmarkFolderDialog.java | 6 +- .../EditBookmarkDatabaseViewDialog.java | 33 +++-- .../EditBookmarkFolderDatabaseViewDialog.java | 41 ++++-- .../dialogs/UrlHistoryDialog.java | 22 +-- .../helpers/BookmarksDatabaseHelper.java | 3 +- .../views/CheckedLinearLayout.java | 125 ++++++++++++++++++ .../layout/appbar_spinner_dropdown_item.xml | 41 ++++-- .../main/res/layout/appbar_spinner_item.xml | 35 +++-- .../databaseview_spinner_dropdown_items.xml | 50 +++++++ .../res/layout/databaseview_spinner_item.xml | 48 +++++++ app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values/colors.xml | 3 + 30 files changed, 508 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java create mode 100644 app/src/main/res/layout/databaseview_spinner_dropdown_items.xml create mode 100644 app/src/main/res/layout/databaseview_spinner_item.xml diff --git a/.idea/dictionaries/soren.xml b/.idea/dictionaries/soren.xml index 8814f0c5..6bd3f77e 100644 --- a/.idea/dictionaries/soren.xml +++ b/.idea/dictionaries/soren.xml @@ -6,6 +6,7 @@ adsense adservers adview + affero amiunique amoled androidcentral @@ -88,6 +89,7 @@ konqueror kufc león + licensors linearlayout listview logins @@ -102,6 +104,7 @@ nightmode nist nojs + noncommercially oname openkeychain openpgp @@ -121,6 +124,7 @@ referer refreshlayout relativelayout + relicensing remarketing requery roadmap @@ -148,6 +152,8 @@ subdomain subdomains subfolders + sublicenses + sublicensing sublists sufficientlysecure swiperefreshlayout @@ -176,6 +182,7 @@ websocket webview whatismyip + wipo wouldn xmlhttprequest yoyo diff --git a/app/src/main/assets/de/about_licenses_dark.html b/app/src/main/assets/de/about_licenses_dark.html index d239bb7d..18b24f36 100644 --- a/app/src/main/assets/de/about_licenses_dark.html +++ b/app/src/main/assets/de/about_licenses_dark.html @@ -48,6 +48,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

diff --git a/app/src/main/assets/de/about_licenses_light.html b/app/src/main/assets/de/about_licenses_light.html index b224f444..74116fa6 100644 --- a/app/src/main/assets/de/about_licenses_light.html +++ b/app/src/main/assets/de/about_licenses_light.html @@ -47,6 +47,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

diff --git a/app/src/main/assets/en/about_licenses_dark.html b/app/src/main/assets/en/about_licenses_dark.html index 97bf1fb1..99cb2c6e 100644 --- a/app/src/main/assets/en/about_licenses_dark.html +++ b/app/src/main/assets/en/about_licenses_dark.html @@ -46,6 +46,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

diff --git a/app/src/main/assets/en/about_licenses_light.html b/app/src/main/assets/en/about_licenses_light.html index ecb7d54a..8fd7c674 100644 --- a/app/src/main/assets/en/about_licenses_light.html +++ b/app/src/main/assets/en/about_licenses_light.html @@ -46,6 +46,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

diff --git a/app/src/main/assets/es/about_licenses_dark.html b/app/src/main/assets/es/about_licenses_dark.html index 5046b13f..66318aab 100644 --- a/app/src/main/assets/es/about_licenses_dark.html +++ b/app/src/main/assets/es/about_licenses_dark.html @@ -48,6 +48,14 @@

Librerías

Navegador privado está construido con la librería de soporte de android, que se libera bajo la Licencia Apache 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Iconos

diff --git a/app/src/main/assets/es/about_licenses_light.html b/app/src/main/assets/es/about_licenses_light.html index a1607e69..5ff4c600 100644 --- a/app/src/main/assets/es/about_licenses_light.html +++ b/app/src/main/assets/es/about_licenses_light.html @@ -48,6 +48,14 @@

Librerías

Navegador privado está construido con la librería de soporte de android, que se libera bajo la Licencia Apache 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Iconos

diff --git a/app/src/main/assets/it/about_licenses_dark.html b/app/src/main/assets/it/about_licenses_dark.html index 878dc7fe..b9244d9d 100644 --- a/app/src/main/assets/it/about_licenses_dark.html +++ b/app/src/main/assets/it/about_licenses_dark.html @@ -51,6 +51,14 @@

Librerie

Privacy Browser è sviluppato con la Android Support Library, che è rilasciata con Licenza Apache 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icone

diff --git a/app/src/main/assets/it/about_licenses_light.html b/app/src/main/assets/it/about_licenses_light.html index a1bccd73..6759c412 100644 --- a/app/src/main/assets/it/about_licenses_light.html +++ b/app/src/main/assets/it/about_licenses_light.html @@ -51,6 +51,14 @@

Librerie

Privacy Browser è sviluppato con la Android Support Library, che è rilasciata con Licenza Apache 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icone

diff --git a/app/src/main/assets/ru/about_licenses_dark.html b/app/src/main/assets/ru/about_licenses_dark.html index cd6badf1..2fdeef66 100644 --- a/app/src/main/assets/ru/about_licenses_dark.html +++ b/app/src/main/assets/ru/about_licenses_dark.html @@ -46,6 +46,14 @@

Библиотеки

Privacy Browser создан с использованием Android Support Library, которая выпущена под Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Иконки

diff --git a/app/src/main/assets/ru/about_licenses_light.html b/app/src/main/assets/ru/about_licenses_light.html index bd012547..3aacc9ac 100644 --- a/app/src/main/assets/ru/about_licenses_light.html +++ b/app/src/main/assets/ru/about_licenses_light.html @@ -46,6 +46,14 @@

Библиотеки

Privacy Browser создан с использованием Android Support Library, которая выпущена под Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Иконки

diff --git a/app/src/main/assets/tr/about_licenses_dark.html b/app/src/main/assets/tr/about_licenses_dark.html index 97bf1fb1..99cb2c6e 100644 --- a/app/src/main/assets/tr/about_licenses_dark.html +++ b/app/src/main/assets/tr/about_licenses_dark.html @@ -46,6 +46,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

diff --git a/app/src/main/assets/tr/about_licenses_light.html b/app/src/main/assets/tr/about_licenses_light.html index ecb7d54a..8fd7c674 100644 --- a/app/src/main/assets/tr/about_licenses_light.html +++ b/app/src/main/assets/tr/about_licenses_light.html @@ -46,6 +46,14 @@

Libraries

Privacy Browser is built with the Android Support Library, which is released under the Apache License 2.0.

+

The free flavor of Privacy Browser is built with Firebase Ads, + which is released under the Android Software Development Kit License.

+ +

Classes

+

com.stoutner.privacybrowser.views.CheckedLinearLayout is a modified version of a class contained in the + Android Camera source code. + The original file was released under the Apache License 2.0. + The modified file is released under the GPLv3+ license.

Icons

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 576e6532..38584187 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksActivity.java @@ -203,9 +203,6 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma bookmarkCursor.close(); }); - // Get a handle for the activity. - Activity activity = this; - // Handle long presses on the list view. bookmarksListView.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() { // Instantiate the common variables. @@ -680,10 +677,10 @@ public class BookmarksActivity extends AppCompatActivity implements CreateBookma // Get new folder name string. String folderNameString = createFolderNameEditText.getText().toString(); - // Get the new folder icon `Bitmap`. + // Get the new folder icon bitmap. Bitmap folderIconBitmap; if (defaultFolderIconRadioButton.isChecked()) { // Use the default folder icon. - // Get the default folder icon and convert it to a `Bitmap`. + // Get the default folder icon and convert it to a bitmap. Drawable folderIconDrawable = folderIconImageView.getDrawable(); BitmapDrawable folderIconBitmapDrawable = (BitmapDrawable) folderIconDrawable; folderIconBitmap = folderIconBitmapDrawable.getBitmap(); 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 dd9c42cf..70bd7735 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/BookmarksDatabaseViewActivity.java @@ -60,6 +60,7 @@ import com.stoutner.privacybrowser.dialogs.EditBookmarkFolderDatabaseViewDialog; import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper; import java.io.ByteArrayOutputStream; +import java.util.Arrays; public class BookmarksDatabaseViewActivity extends AppCompatActivity implements EditBookmarkDatabaseViewDialog.EditBookmarkDatabaseViewListener, EditBookmarkFolderDatabaseViewDialog.EditBookmarkFolderDatabaseViewListener { @@ -128,7 +129,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 `0` is to specify a database version, but that is set instead using a constant in `BookmarksDatabaseHelper`. + // Initialize the database handler. 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". @@ -143,13 +144,60 @@ public class BookmarksDatabaseViewActivity extends AppCompatActivity implements // Combine `matrixCursor` and `foldersCursor`. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); + + // Get the default folder bitmap. `ContextCompat` must be used until the minimum API >= 21. + Drawable defaultFolderDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.folder_blue_bitmap); + + // Cast the default folder drawable to a `BitmapDrawable`. + BitmapDrawable defaultFolderBitmapDrawable = (BitmapDrawable) defaultFolderDrawable; + + // Remove the incorrect lint warning that `.getBitmap()` might be null. + assert defaultFolderBitmapDrawable != null; + + // Convert the default folder `BitmapDrawable` to a bitmap. + Bitmap defaultFolderBitmap = defaultFolderBitmapDrawable.getBitmap(); + + // Create a resource cursor adapter for the spinner. ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(this, R.layout.appbar_spinner_item, foldersMergeCursor, 0) { @Override public void bindView(View view, Context context, Cursor cursor) { - // Get a handle for the spinner item text view. + // Get handles for the spinner views. + ImageView spinnerItemImageView = view.findViewById(R.id.spinner_item_imageview); TextView spinnerItemTextView = view.findViewById(R.id.spinner_item_textview); + // Set the folder icon according to the type. + if (foldersMergeCursor.getPosition() > 1) { // Set a user folder icon. + // Initialize a default folder icon byte array output stream. + ByteArrayOutputStream defaultFolderIconByteArrayOutputStream = new ByteArrayOutputStream(); + + // Covert the default folder bitmap to a PNG and store it in the output stream. `0` is for lossless compression (the only option for a PNG). + defaultFolderBitmap.compress(Bitmap.CompressFormat.PNG, 0, defaultFolderIconByteArrayOutputStream); + + // Convert the default folder icon output stream to a byte array. + byte[] defaultFolderIconByteArray = defaultFolderIconByteArrayOutputStream.toByteArray(); + + + // Get the folder icon byte array from the cursor. + byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHelper.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); + + + // Set the icon according to the type. + if (Arrays.equals(folderIconByteArray, defaultFolderIconByteArray)) { // The default folder icon is used. + // Set a smaller and darker folder icon, which works well with the spinner. + spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_dark_blue)); + } else { // A custom folder icon is uses. + // Set the folder image stored in the cursor. + spinnerItemImageView.setImageBitmap(folderIconBitmap); + } + } else { // Set the `All Folders` or `Home Folder` icon. + // Set the gray folder image. `ContextCompat` must be used until the minimum API >= 21. + spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_gray)); + } + // Set the text view to display the folder name. spinnerItemTextView.setText(cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))); } 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 a7a96616..83aa93f9 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java @@ -94,7 +94,7 @@ public class CreateBookmarkFolderDialog extends AppCompatDialogFragment { }); - // Create an `AlertDialog` from the `AlertDialog.Builder`. + // Create an alert dialog from the `AlertDialog.Builder`. final AlertDialog alertDialog = dialogBuilder.create(); // Remove the warning below that `getWindow()` might be null. @@ -108,7 +108,7 @@ public class CreateBookmarkFolderDialog extends AppCompatDialogFragment { // Show the keyboard when the `Dialog` is displayed on the screen. alertDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - // The `AlertDialog` must be shown before items in the alert dialog can be modified. + // The alert dialog must be shown before items in the alert dialog can be modified. alertDialog.show(); // Get handles for the views in the dialog. @@ -147,7 +147,7 @@ public class CreateBookmarkFolderDialog extends AppCompatDialogFragment { } }); - // Allow the `enter` key on the keyboard to create the folder from `create_folder_name_edittext`. + // Allow the enter key on the keyboard to create the folder from `create_folder_name_edittext`. folderNameEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> { // If the event is a key-down on the `enter` key, select the `PositiveButton` `Create`. if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && createButton.isEnabled()) { // The enter key was pressed and the create button is enabled. 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 7328080e..5abda5b9 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkDatabaseViewDialog.java @@ -32,6 +32,7 @@ import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.annotation.NonNull; // `AppCompatDialogFragment` is required instead of `DialogFragment` or an error is produced on API <=22. +import android.support.v4.content.ContextCompat; import android.support.v4.widget.ResourceCursorAdapter; import android.support.v7.app.AppCompatDialogFragment; import android.text.Editable; @@ -194,19 +195,19 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment { // Display `currentIconBitmap` in `edit_bookmark_current_icon`. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a `Bitmap` of the favorite icon from `MainWebViewActivity` and display it in `edit_bookmark_web_page_favorite_icon`. + // Get a bitmap of the favorite icon from `MainWebViewActivity` and display it in `edit_bookmark_web_page_favorite_icon`. newFavoriteIconImageView.setImageBitmap(MainWebViewActivity.favoriteIconBitmap); // Populate the bookmark name and URL `EditTexts`. nameEditText.setText(currentBookmarkName); urlEditText.setText(currentUrl); - // Setup a `MatrixCursor` "Home Folder". + // Setup a matrix cursor for "Home Folder". String[] matrixCursorColumnNames = {BookmarksDatabaseHelper._ID, BookmarksDatabaseHelper.BOOKMARK_NAME}; MatrixCursor matrixCursor = new MatrixCursor(matrixCursorColumnNames); matrixCursor.addRow(new Object[]{HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)}); - // Get a `Cursor` with the list of all the folders. + // Get a cursor with the list of all the folders. Cursor foldersCursor = bookmarksDatabaseHelper.getAllFolders(); // Combine `matrixCursor` and `foldersCursor`. @@ -215,20 +216,36 @@ public class EditBookmarkDatabaseViewDialog extends AppCompatDialogFragment { // Remove the incorrect lint warning below that `getContext()` might be null. assert getContext() != null; - // Create a `ResourceCursorAdapter` for the `Spinner`. `0` specifies no flags.; - ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.spinner_item, foldersMergeCursor, 0) { + // Create a resource cursor adapter for the spinner. + ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.databaseview_spinner_item, foldersMergeCursor, 0) { @Override public void bindView(View view, Context context, Cursor cursor) { - // Get a handle for the `Spinner` item `TextView`. + // Get handles for the spinner views. + ImageView spinnerItemImageView = view.findViewById(R.id.spinner_item_imageview); TextView spinnerItemTextView = view.findViewById(R.id.spinner_item_textview); - // Set the `TextView` to display the folder name. + // Set the folder icon according to the type. + if (foldersMergeCursor.getPosition() == 0) { // Set the `Home Folder` icon. + // Set the gray folder image. `ContextCompat` must be used until the minimum API >= 21. + spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_gray)); + } else { // Set a user folder icon. + // Get the folder icon byte array. + byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHelper.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); + + // Set the folder icon. + spinnerItemImageView.setImageBitmap(folderIconBitmap); + } + + // Set the text view 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.spinner_dropdown_items); + foldersCursorAdapter.setDropDownViewResource(R.layout.databaseview_spinner_dropdown_items); // Set the adapter for the folder `Spinner`. folderSpinner.setAdapter(foldersCursorAdapter); 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 75e0d916..0f691433 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/EditBookmarkFolderDatabaseViewDialog.java @@ -32,6 +32,7 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; import android.support.v4.widget.ResourceCursorAdapter; // `AppCompatDialogFragment` is required instead of `DialogFragment` or an error is produced on API <=22. import android.support.v7.app.AppCompatDialogFragment; @@ -189,49 +190,65 @@ public class EditBookmarkFolderDatabaseViewDialog extends AppCompatDialogFragmen // Convert the byte array to a `Bitmap` beginning at the first byte and ending at the last. Bitmap currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.length); - // Display `currentIconBitmap` in `edit_bookmark_current_icon`. + // Display the current icon bitmap in `edit_bookmark_current_icon`. currentIconImageView.setImageBitmap(currentIconBitmap); - // Get a `Bitmap` of the favorite icon from `MainWebViewActivity` and display it in `edit_bookmark_web_page_favorite_icon`. + // Get a bitmap of the favorite icon from `MainWebViewActivity` and display it in `edit_bookmark_web_page_favorite_icon`. newFavoriteIconImageView.setImageBitmap(MainWebViewActivity.favoriteIconBitmap); - // Populate the folder name `EditText`. + // Populate the folder name edit text. nameEditText.setText(currentFolderName); - // Setup a `MatrixCursor` "Home Folder". + // Setup a matrix cursor for "Home Folder". String[] matrixCursorColumnNames = {BookmarksDatabaseHelper._ID, BookmarksDatabaseHelper.BOOKMARK_NAME}; MatrixCursor matrixCursor = new MatrixCursor(matrixCursorColumnNames); matrixCursor.addRow(new Object[]{HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)}); - // Initialize a `StringBuilder` to track the folders not to display in the `Spinner` and populate it with the current folder. + // Initialize a string builder to track the folders not to display in the spinner and populate it with the current folder. exceptFolders = new StringBuilder(DatabaseUtils.sqlEscapeString(currentFolderName)); // Add all subfolders of the current folder to the list of folders not to display. addSubfoldersToExceptFolders(currentFolderName); - // Get a `Cursor` with the list of all the folders. + // Get a cursor with the list of all the folders. Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders.toString()); - // Combine `matrixCursor` and `foldersCursor`. + // Combine the matrix cursor and the folders cursor. MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor}); // Remove the incorrect lint warning that `getContext()` might be null. assert getContext() != null; - // Create a `ResourceCursorAdapter` for the `Spinner`. `0` specifies no flags.; - ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.spinner_item, foldersMergeCursor, 0) { + // Create a resource cursor adapter for the spinner. + ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.databaseview_spinner_item, foldersMergeCursor, 0) { @Override public void bindView(View view, Context context, Cursor cursor) { - // Get a handle for the `Spinner` item `TextView`. + // Get handles for the spinner views. + ImageView spinnerItemImageView = view.findViewById(R.id.spinner_item_imageview); TextView spinnerItemTextView = view.findViewById(R.id.spinner_item_textview); - // Set the `TextView` to display the folder name. + // Set the folder icon according to the type. + if (foldersMergeCursor.getPosition() == 0) { // Set the `Home Folder` icon. + // Set the gray folder image. `ContextCompat` must be used until the minimum API >= 21. + spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_gray)); + } else { // Set a user folder icon. + // Get the folder icon byte array. + byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHelper.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); + + // Set the folder icon. + spinnerItemImageView.setImageBitmap(folderIconBitmap); + } + + // Set the text view 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.spinner_dropdown_items); + foldersCursorAdapter.setDropDownViewResource(R.layout.databaseview_spinner_dropdown_items); // Set the adapter for the folder `Spinner`. folderSpinner.setAdapter(foldersCursorAdapter); diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.java b/app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.java index 9b9d9f61..a593f5cf 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.java +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.java @@ -1,5 +1,5 @@ /* - * Copyright © 2016-2018 Soren Stoutner . + * Copyright © 2016-2019 Soren Stoutner . * * This file is part of Privacy Browser . * @@ -57,37 +57,37 @@ public class UrlHistoryDialog extends AppCompatDialogFragment{ private int currentPageId; public static UrlHistoryDialog loadBackForwardList(Context context, WebBackForwardList webBackForwardList) { - // Create `argumentsBundle`. + // Create an arguments bundle. Bundle argumentsBundle = new Bundle(); - // Store `currentPageIndex`. + // Store the current page index. int currentPageIndex = webBackForwardList.getCurrentIndex(); - // Setup `urlArrayList` and `iconArrayList`. + // Setup the URL array list and the icon array list. ArrayList urlArrayList = new ArrayList<>(); ArrayList iconBase64StringArrayList = new ArrayList<>(); - // Get the default favorite icon `Drawable`. + // Get the default favorite icon drawable. `ContextCompat` must be used until the minimum API >= 21. Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world); - // Convert `defaultFavoriteIconDrawable` to a `BitmapDrawable`. + // Convert the default favorite icon drawable to a `BitmapDrawable`. BitmapDrawable defaultFavoriteIconBitmapDrawable = (BitmapDrawable) defaultFavoriteIconDrawable; // Remove the incorrect lint error that `getBitmap()` might be null. assert defaultFavoriteIconBitmapDrawable != null; - // Extract a `Bitmap` from `defaultFavoriteIconBitmapDrawable`. + // Extract a `Bitmap` from the default favorite icon `BitmapDrawable`. Bitmap defaultFavoriteIcon = defaultFavoriteIconBitmapDrawable.getBitmap(); - // Populate `urlArrayList` and `iconArrayList` from `webBackForwardList`. + // Populate the URL array list and the icon array list from `webBackForwardList`. for (int i=0; i < webBackForwardList.getSize(); i++) { // Store the URL. urlArrayList.add(webBackForwardList.getItemAtIndex(i).getUrl()); - // Create a variable to store the icon `Bitmap`. + // Create a variable to store the icon bitmap. Bitmap iconBitmap; - // Store the icon `Bitmap`. + // Store the icon bitmap. if (webBackForwardList.getItemAtIndex(i).getFavicon() == null) { // If `webBackForwardList` does not have a favorite icon, use Privacy Browser's default world icon. iconBitmap = defaultFavoriteIcon; @@ -119,7 +119,7 @@ public class UrlHistoryDialog extends AppCompatDialogFragment{ argumentsBundle.putStringArrayList("URL_History", urlArrayList); argumentsBundle.putStringArrayList("Favorite_Icons", iconBase64StringArrayList); - // Add `argumentsBundle` to this instance of `UrlHistoryDialog`. + // Add the arguments bundle to this instance of `UrlHistoryDialog`. UrlHistoryDialog thisUrlHistoryDialog = new UrlHistoryDialog(); thisUrlHistoryDialog.setArguments(argumentsBundle); return thisUrlHistoryDialog; 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 85089314..a2af6451 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/BookmarksDatabaseHelper.java @@ -295,8 +295,7 @@ public class BookmarksDatabaseHelper extends SQLiteOpenHelper { " 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. + // Return the results as a cursor. The cursor cannot be closed because it is used in the parent activity. return bookmarksDatabase.rawQuery(GET_ALL_FOLDERS, null); } diff --git a/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java b/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java new file mode 100644 index 00000000..e9bc8047 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/views/CheckedLinearLayout.java @@ -0,0 +1,125 @@ +/* + * Copyright © 2019 Soren Stoutner . + * + * This file is part of 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 . + * + * + * + * This file is a modified version of . + * + * The original licensing information is below. + * + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.stoutner.privacybrowser.views; + +import android.content.Context; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.view.View; +import android.widget.Checkable; +import android.widget.LinearLayout; + +public class CheckedLinearLayout extends LinearLayout implements Checkable { + private boolean isCurrentlyChecked; + private static final int[] CHECKED_STATE_SET = { + android.R.attr.state_checked + }; + + public CheckedLinearLayout(Context context) { + // Run the default commands. + super(context); + } + + public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet) { + // Run the default commands. + super(context, attributeSet); + } + + public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet, int defaultStyleAttribute) { + // Run the default commands. + super(context, attributeSet, defaultStyleAttribute); + } + + /* This constructor can only be added once the minimum API >= 21. + public CheckedLinearLayout(Context context, @Nullable AttributeSet attributeSet, int defaultStyleAttribute, int defaultStyleResource) { + // Run the default commands. + super(context, attributeSet, defaultStyleAttribute, defaultStyleResource); + } */ + + @Override + public boolean isChecked() { + // Return the checked status. + return isCurrentlyChecked; + } + + @Override + public void setChecked(boolean checked) { + // Only process the command if a change is requested. + if (isCurrentlyChecked != checked) { + // Update the is currently checked tracker. + isCurrentlyChecked = checked; + + // Refresh the drawable state. + refreshDrawableState(); + + // Propagate the checked status to the child views. + for (int i = 0; i < getChildCount(); i++) { + // Get a handle for the child view. + View childView = getChildAt(i); + + // Propagate the checked status if the child view is checkable. + if (childView instanceof Checkable) { + // Cast the child view to `Checkable`. + Checkable checkableChildView = (Checkable) childView; + + // Set the checked status. + checkableChildView.setChecked(checked); + } + } + } + } + + @Override + public void toggle() { + // Toggle the state. + setChecked(!isCurrentlyChecked); + } + + @Override + public int[] onCreateDrawableState(int extraSpace) { + final int[] drawableState = super.onCreateDrawableState(extraSpace + 1); + + if (isCurrentlyChecked) { + mergeDrawableStates(drawableState, CHECKED_STATE_SET); + } + + return drawableState; + } +} diff --git a/app/src/main/res/layout/appbar_spinner_dropdown_item.xml b/app/src/main/res/layout/appbar_spinner_dropdown_item.xml index d71b180d..a6586750 100644 --- a/app/src/main/res/layout/appbar_spinner_dropdown_item.xml +++ b/app/src/main/res/layout/appbar_spinner_dropdown_item.xml @@ -1,7 +1,7 @@ - - \ No newline at end of file + android:orientation="horizontal" + android:background="?attr/spinnerBackground" > + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/appbar_spinner_item.xml b/app/src/main/res/layout/appbar_spinner_item.xml index 3e7cc3c3..5c61a208 100644 --- a/app/src/main/res/layout/appbar_spinner_item.xml +++ b/app/src/main/res/layout/appbar_spinner_item.xml @@ -1,7 +1,7 @@ - \ No newline at end of file + android:orientation="horizontal" + tools:ignore="UseCompoundDrawables" > + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/databaseview_spinner_dropdown_items.xml b/app/src/main/res/layout/databaseview_spinner_dropdown_items.xml new file mode 100644 index 00000000..5e3c1ff0 --- /dev/null +++ b/app/src/main/res/layout/databaseview_spinner_dropdown_items.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/databaseview_spinner_item.xml b/app/src/main/res/layout/databaseview_spinner_item.xml new file mode 100644 index 00000000..e254b498 --- /dev/null +++ b/app/src/main/res/layout/databaseview_spinner_item.xml @@ -0,0 +1,48 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 6ab409af..789a3f6f 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -242,6 +242,7 @@ Carpeta: Carpeta superior: Mostrar orden: + No se puede deseleccionar un favorito mientras la carpeta superior está seleccionada. Peticiones diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 79deaeb8..3c3c1495 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -241,6 +241,7 @@ Cartella: Cartella superiore: Ordine di visualizzazione: + Non è possibile deselezionare un segnalibro mentre la cartella di appartenenza è selezionate. Richieste diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 628cc795..3217b5dc 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -238,6 +238,7 @@ Папка: Родительская папка: Порядок отображения: + Невозможно отменить выбор закладки пока выбрана родительская папка. Запросы diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 40922729..1f209cc3 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -237,6 +237,7 @@ Klasör: Üst Klasör: Görüntüleme düzeni: + Üst klasör seçiliyken bir yer iminin seçimi kaldırılamaz. İstekler diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2d4448e1..0bcee21d 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -23,6 +23,9 @@ #66000000 #FF000000 + #11000000 + #22000000 + #33000000 #FFE3F2FD #FFBBDEFB -- 2.43.0