]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/dialogs/CreateBookmarkFolderDialog.java
Make the favorite icon tab aware.
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / CreateBookmarkFolderDialog.java
1 /*
2  * Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
5  *
6  * Privacy Browser is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Privacy Browser is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Privacy Browser.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.dialogs;
21
22 import android.annotation.SuppressLint;
23 import android.app.AlertDialog;
24 import android.app.Dialog;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.database.Cursor;
28 import android.graphics.Bitmap;
29 import android.graphics.BitmapFactory;
30 import android.os.Bundle;
31 import android.text.Editable;
32 import android.text.TextWatcher;
33 import android.view.KeyEvent;
34 import android.view.View;
35 import android.view.WindowManager;
36 import android.widget.Button;
37 import android.widget.EditText;
38 import android.widget.ImageView;
39
40 import androidx.annotation.NonNull;
41 import androidx.fragment.app.DialogFragment;  // The AndroidX dialog fragment must be used or an error is produced on API <=22.
42
43 import com.stoutner.privacybrowser.R;
44 import com.stoutner.privacybrowser.activities.MainWebViewActivity;
45 import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
46
47 import java.io.ByteArrayOutputStream;
48
49 public class CreateBookmarkFolderDialog extends DialogFragment {
50     // The public interface is used to send information back to the parent activity.
51     public interface CreateBookmarkFolderListener {
52         void onCreateBookmarkFolder(DialogFragment dialogFragment, Bitmap favoriteIconBitmap);
53     }
54
55     // `createBookmarkFolderListener` is used in `onAttach()` and `onCreateDialog`.
56     private CreateBookmarkFolderListener createBookmarkFolderListener;
57
58     public void onAttach(Context context) {
59         super.onAttach(context);
60
61         // Get a handle for `createBookmarkFolderListener` from the launching context.
62         createBookmarkFolderListener = (CreateBookmarkFolderListener) context;
63     }
64
65     public static CreateBookmarkFolderDialog createBookmarkFolder(Bitmap favoriteIconBitmap) {
66         // Create a favorite icon byte array output stream.
67         ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
68
69         // Convert the favorite icon to a PNG and place it in the byte array output stream.  `0` is for lossless compression (the only option for a PNG).
70         favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
71
72         // Convert the byte array output stream to a byte array.
73         byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
74
75         // Create an arguments bundle.
76         Bundle argumentsBundle = new Bundle();
77
78         // Store the favorite icon in the bundle.
79         argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray);
80
81         // Create a new instance of the dialog.
82         CreateBookmarkFolderDialog createBookmarkFolderDialog = new CreateBookmarkFolderDialog();
83
84         // Add the bundle to the dialog.
85         createBookmarkFolderDialog.setArguments(argumentsBundle);
86
87         // Return the new dialog.
88         return createBookmarkFolderDialog;
89     }
90
91     // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
92     @SuppressLint("InflateParams")
93     @Override
94     @NonNull
95     public Dialog onCreateDialog(Bundle savedInstanceState) {
96         // Get the arguments.
97         Bundle arguments = getArguments();
98
99         // Remove the incorrect lint warning below that the arguments might be null.
100         assert arguments != null;
101
102         // Get the favorite icon byte array.
103         byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array");
104
105         // Remove the incorrect lint warning below that the favorite icon byte array might be null.
106         assert favoriteIconByteArray != null;
107
108         // Convert the favorite icon byte array to a bitmap.
109         Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
110
111         // Use an alert dialog builder to create the alert dialog.
112         AlertDialog.Builder dialogBuilder;
113
114         // Set the style according to the theme.
115         if (MainWebViewActivity.darkTheme) {
116             dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogDark);
117         } else {
118             dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialogLight);
119         }
120
121         // Set the title.
122         dialogBuilder.setTitle(R.string.create_folder);
123
124         // Remove the warning below that `getLayoutInflater()` might be null.
125         assert getActivity() != null;
126
127         // Set the view.  The parent view is null because it will be assigned by the alert dialog.
128         dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.create_bookmark_folder_dialog, null));
129
130         // Set an `onClick()` listener for the negative button.
131         dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
132             // Do nothing.  The `AlertDialog` will close automatically.
133         });
134
135         // Set an `onClick()` listener fo the positive button.
136         dialogBuilder.setPositiveButton(R.string.create, (DialogInterface dialog, int which) -> {
137             // Return the `DialogFragment` to the parent activity on create.
138             createBookmarkFolderListener.onCreateBookmarkFolder(this, favoriteIconBitmap);
139         });
140
141
142         // Create an alert dialog from the `AlertDialog.Builder`.
143         final AlertDialog alertDialog = dialogBuilder.create();
144
145         // Remove the warning below that `getWindow()` might be null.
146         assert alertDialog.getWindow() != null;
147
148         // Disable screenshots if not allowed.
149         if (!MainWebViewActivity.allowScreenshots) {
150             alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
151         }
152
153         // The alert dialog must be shown before items in the alert dialog can be modified.
154         alertDialog.show();
155
156         // Get handles for the views in the dialog.
157         final Button createButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
158         EditText folderNameEditText = alertDialog.findViewById(R.id.create_folder_name_edittext);
159         ImageView webPageIconImageView = alertDialog.findViewById(R.id.create_folder_web_page_icon);
160
161         // Initially disable the create button.
162         createButton.setEnabled(false);
163
164         // Initialize the database helper.  The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
165         final BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0);
166
167         // Enable the create button if the new folder name is unique.
168         folderNameEditText.addTextChangedListener(new TextWatcher() {
169             @Override
170             public void beforeTextChanged(CharSequence s, int start, int count, int after) {
171                 // Do nothing.
172             }
173
174             @Override
175             public void onTextChanged(CharSequence s, int start, int before, int count) {
176                 // Do nothing.
177             }
178
179             @Override
180             public void afterTextChanged(Editable s) {
181                 // Convert the current text to a string.
182                 String folderName = s.toString();
183
184                 // Check if a folder with the name already exists.
185                 Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(folderName);
186
187                 // Enable the create button if the new folder name is not empty and doesn't already exist.
188                 createButton.setEnabled(!folderName.isEmpty() && (folderExistsCursor.getCount() == 0));
189             }
190         });
191
192         // Allow the enter key on the keyboard to create the folder from `create_folder_name_edittext`.
193         folderNameEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
194             // If the event is a key-down on the `enter` key, select the `PositiveButton` `Create`.
195             if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && createButton.isEnabled()) {  // The enter key was pressed and the create button is enabled.
196                 // Trigger `createBookmarkFolderListener` and return the `DialogFragment` to the parent activity.
197                 createBookmarkFolderListener.onCreateBookmarkFolder(this, favoriteIconBitmap);
198                 // Manually dismiss the `AlertDialog`.
199                 alertDialog.dismiss();
200                 // Consume the event.
201                 return true;
202             } else {  // If any other key was pressed, or if the create button is currently disabled, do not consume the event.
203                 return false;
204             }
205         });
206
207         // Display the current favorite icon.
208         webPageIconImageView.setImageBitmap(favoriteIconBitmap);
209
210         // Return the alert dialog.
211         return alertDialog;
212     }
213 }