a10e574a5a003ff012849fb6a1ce5e77373e0929
[PrivacyBrowser.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / CreateBookmarkDialog.kt
1 /*
2  * Copyright © 2016-2020 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.Dialog
24 import android.content.Context
25 import android.content.DialogInterface
26 import android.graphics.Bitmap
27 import android.graphics.BitmapFactory
28 import android.graphics.drawable.BitmapDrawable
29 import android.graphics.drawable.Drawable
30 import android.os.Bundle
31 import android.view.KeyEvent
32 import android.view.View
33 import android.view.WindowManager
34 import android.widget.EditText
35
36 import androidx.appcompat.app.AlertDialog
37 import androidx.fragment.app.DialogFragment
38 import androidx.preference.PreferenceManager
39
40 import com.stoutner.privacybrowser.R
41
42 import java.io.ByteArrayOutputStream
43
44 class CreateBookmarkDialog: DialogFragment() {
45     // The public interface is used to send information back to the parent activity.
46     interface CreateBookmarkListener {
47         fun onCreateBookmark(dialogFragment: DialogFragment, favoriteIconBitmap: Bitmap)
48     }
49
50     // The create bookmark listener is initialized in `onAttach()` and used in `onCreateDialog()`.
51     private lateinit var createBookmarkListener: CreateBookmarkListener
52
53     override fun onAttach(context: Context) {
54         // Run the default commands.
55         super.onAttach(context)
56
57         // Get a handle for the create bookmark listener from the launching context.
58         createBookmarkListener = context as CreateBookmarkListener
59     }
60
61     companion object {
62         // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin.  Also, the function can then be moved out of a companion object and just become a package-level function.
63         @JvmStatic
64         fun createBookmark(urlString: String, titleString: String, favoriteIconBitmap: Bitmap): CreateBookmarkDialog {
65             // Create a favorite icon byte array output stream.
66             val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
67
68             // 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).
69             favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
70
71             // Convert the byte array output stream to a byte array.
72             val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
73
74             // Create an arguments bundle.
75             val argumentsBundle = Bundle()
76
77             // Store the variables in the bundle.
78             argumentsBundle.putString("url_string", urlString)
79             argumentsBundle.putString("title_string", titleString)
80             argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray)
81
82             // Create a new instance of the dialog.
83             val createBookmarkDialog = CreateBookmarkDialog()
84
85             // Add the bundle to the dialog.
86             createBookmarkDialog.arguments = argumentsBundle
87
88             // Return the new dialog.
89             return createBookmarkDialog
90         }
91     }
92
93     // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
94     @SuppressLint("InflateParams")
95     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
96         // Get the arguments.
97         val arguments = requireArguments()
98
99         // Get the contents of the arguments.
100         val urlString = arguments.getString("url_string")
101         val titleString = arguments.getString("title_string")
102         val favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array")!!
103
104         // Convert the favorite icon byte array to a bitmap.
105         val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
106
107         // Use an alert dialog builder to create the dialog.
108         val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
109
110         // Set the title.
111         dialogBuilder.setTitle(R.string.create_bookmark)
112
113         // Create a drawable version of the favorite icon.
114         val favoriteIconDrawable: Drawable = BitmapDrawable(resources, favoriteIconBitmap)
115
116         // Set the icon.
117         dialogBuilder.setIcon(favoriteIconDrawable)
118
119         // Set the view.  The parent view is `null` because it will be assigned by the alert dialog.
120         dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.create_bookmark_dialog, null))
121
122         // Set a listener on the cancel button.  Using `null` as the listener closes the dialog without doing anything else.
123         dialogBuilder.setNegativeButton(R.string.cancel, null)
124
125         // Set a listener on the create button.
126         dialogBuilder.setPositiveButton(R.string.create) { _: DialogInterface, _: Int ->
127             // Return the dialog fragment and the favorite icon bitmap to the parent activity.
128             createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap)
129         }
130
131         // Create an alert dialog from the builder.
132         val alertDialog = dialogBuilder.create()
133
134
135         // Get a handle for the shared preferences.
136         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
137
138         // Get the screenshot preference.
139         val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
140
141         // Disable screenshots if not allowed.
142         if (!allowScreenshots) {
143             alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
144         }
145
146         // The alert dialog needs to be shown before the contents can be modified.
147         alertDialog.show()
148
149         // Get a handle for the edit texts.
150         val createBookmarkNameEditText = alertDialog.findViewById<EditText>(R.id.create_bookmark_name_edittext)!!
151         val createBookmarkUrlEditText = alertDialog.findViewById<EditText>(R.id.create_bookmark_url_edittext)!!
152
153         // Set the initial texts for the edit texts.
154         createBookmarkNameEditText.setText(titleString)
155         createBookmarkUrlEditText.setText(urlString)
156
157         // Allow the enter key on the keyboard to create the bookmark from the create bookmark name edit text.
158         createBookmarkNameEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
159             // Check the key code and event.
160             if (keyCode == KeyEvent.KEYCODE_ENTER && keyEvent.action == KeyEvent.ACTION_DOWN) {  // The event is a key-down on the enter key.
161                 // Trigger the create bookmark listener and return the dialog fragment and the favorite icon bitmap to the parent activity.
162                 createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap)
163
164                 // Manually dismiss the alert dialog.
165                 alertDialog.dismiss()
166
167                 // Consume the event.
168                 return@setOnKeyListener true
169             } else {  // Some other key was pressed.
170                 // Do not consume the event.
171                 return@setOnKeyListener false
172             }
173         }
174
175         // Allow the enter key on the keyboard to create the bookmark from create bookmark URL edit text.
176         createBookmarkUrlEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
177             // Check the key code and event.
178             if (keyCode == KeyEvent.KEYCODE_ENTER && keyEvent.action == KeyEvent.ACTION_DOWN) {  // The event is a key-down on the enter key.
179                 // Trigger the create bookmark listener and return the dialog fragment and the favorite icon bitmap to the parent activity.
180                 createBookmarkListener.onCreateBookmark(this, favoriteIconBitmap)
181
182                 // Manually dismiss the alert dialog.
183                 alertDialog.dismiss()
184
185                 // Consume the event.
186                 return@setOnKeyListener true
187             } else { // Some other key was pressed.
188                 // Do not consume the event.
189                 return@setOnKeyListener false
190             }
191         }
192
193         // Return the alert dialog.
194         return alertDialog
195     }
196 }