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