]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blob - app/src/main/java/com/stoutner/privacybrowser/dialogs/UrlHistoryDialog.kt
Switch the FragmentPagerAdapters to FragmentStateAdapters. https://redmine.stoutner...
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / dialogs / UrlHistoryDialog.kt
1 /*
2  * Copyright 2016-2023 Soren Stoutner <soren@stoutner.com>.
3  *
4  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
5  *
6  * Privacy Browser Android 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 Android 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 Android.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package com.stoutner.privacybrowser.dialogs
21
22 import android.app.Dialog
23 import android.content.Context
24 import android.content.DialogInterface
25 import android.graphics.drawable.BitmapDrawable
26 import android.os.Bundle
27 import android.view.View
28 import android.view.WindowManager
29 import android.widget.AdapterView
30 import android.widget.AdapterView.OnItemClickListener
31 import android.widget.ListView
32 import android.widget.TextView
33
34 import androidx.appcompat.app.AlertDialog
35 import androidx.core.content.ContextCompat
36 import androidx.fragment.app.DialogFragment
37 import androidx.preference.PreferenceManager
38
39 import com.stoutner.privacybrowser.R
40 import com.stoutner.privacybrowser.activities.MainWebViewActivity
41 import com.stoutner.privacybrowser.adapters.HistoryArrayAdapter
42 import com.stoutner.privacybrowser.dataclasses.HistoryDataClass
43 import com.stoutner.privacybrowser.views.NestedScrollWebView
44
45 // Define the class constants.
46 private const val WEBVIEW_FRAGMENT_ID = "webview_fragment_id"
47
48 class UrlHistoryDialog : DialogFragment() {
49     companion object {
50         fun loadBackForwardList(webViewFragmentId: Long): UrlHistoryDialog {
51             // Create an arguments bundle.
52             val argumentsBundle = Bundle()
53
54             // Store the WebView fragment ID in the bundle.
55             argumentsBundle.putLong(WEBVIEW_FRAGMENT_ID, webViewFragmentId)
56
57             // Create a new instance of the URL history dialog.
58             val urlHistoryDialog = UrlHistoryDialog()
59
60             // Add the arguments bundle to the new dialog.
61             urlHistoryDialog.arguments = argumentsBundle
62
63             // Return the new dialog.
64             return urlHistoryDialog
65         }
66     }
67
68     // Declare the class variables.
69     private lateinit var navigateHistoryListener: NavigateHistoryListener
70
71     // The public interface is used to send information back to the parent activity.
72     interface NavigateHistoryListener {
73         fun navigateHistory(url: String, steps: Int)
74     }
75
76     override fun onAttach(context: Context) {
77         // Run the default commands.
78         super.onAttach(context)
79
80         // Get a handle for the listener from the launching context.
81         navigateHistoryListener = context as NavigateHistoryListener
82     }
83
84     override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
85         // Get the WebView fragment ID from the arguments.
86         val webViewFragmentId = requireArguments().getLong(WEBVIEW_FRAGMENT_ID)
87
88         // Get the current position of this WebView fragment.
89         val webViewPosition = MainWebViewActivity.webViewStateAdapter!!.getPositionForId(webViewFragmentId)
90
91         // Get the WebView tab fragment.
92         val webViewTabFragment = MainWebViewActivity.webViewStateAdapter!!.getPageFragment(webViewPosition)
93
94         // Get the fragment view.
95         val fragmentView = webViewTabFragment.requireView()
96
97         // Get a handle for the current nested scroll WebView.
98         val nestedScrollWebView: NestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview)
99
100         // Get the web back forward list from the nested scroll WebView.
101         val webBackForwardList = nestedScrollWebView.copyBackForwardList()
102
103         // Store the current page index.
104         val currentPageIndex = webBackForwardList.currentIndex
105
106         // Get the default favorite icon drawable.  `ContextCompat` must be used until the minimum API >= 21.
107         val defaultFavoriteIconDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.world)
108
109         // Convert the default favorite icon drawable to a bitmap drawable.
110         val defaultFavoriteIconBitmapDrawable = (defaultFavoriteIconDrawable as BitmapDrawable)
111
112         // Extract a bitmap from the default favorite icon bitmap drawable.
113         val defaultFavoriteIcon = defaultFavoriteIconBitmapDrawable.bitmap
114
115         // Create a history array list.
116         val historyDataClassArrayList = ArrayList<HistoryDataClass>()
117
118         // Populate the history array list, descending from the end of the list so that the newest entries are at the top.  `-1` is needed because the history array list is zero-based.
119         for (i in webBackForwardList.size - 1 downTo 0) {
120             // Store the favorite icon bitmap.
121             val favoriteIconBitmap = if (webBackForwardList.getItemAtIndex(i).favicon == null) {
122                 // If the web back forward list does not have a favorite icon, use Privacy Browser's default world icon.
123                 defaultFavoriteIcon
124             } else {  // Use the icon from the web back forward list.
125                 webBackForwardList.getItemAtIndex(i).favicon
126             }
127
128             // Store the favorite icon and the URL in history entry.
129             val historyDataClassEntry = HistoryDataClass(favoriteIconBitmap!!, webBackForwardList.getItemAtIndex(i).url)
130
131             // Add this history entry to the history array list.
132             historyDataClassArrayList.add(historyDataClassEntry)
133         }
134
135         // Subtract the original current page ID from the array size because the order of the array is reversed so that the newest entries are at the top.  `-1` is needed because the array is zero-based.
136         val currentPageId = webBackForwardList.size - 1 - currentPageIndex
137
138         // Use an alert dialog builder to create the alert dialog.
139         val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
140
141         // Set the title.
142         dialogBuilder.setTitle(R.string.history)
143
144         // Set the view.
145         dialogBuilder.setView(R.layout.url_history_dialog)
146
147         // Setup the clear history button listener.
148         dialogBuilder.setNegativeButton(R.string.clear_history) { _: DialogInterface, _: Int ->
149             // Clear the history.
150             nestedScrollWebView.clearHistory()
151         }
152
153         // Set the close button listener.  Using `null` as the listener closes the dialog without doing anything else.
154         dialogBuilder.setPositiveButton(R.string.close, null)
155
156         // Create an alert dialog from the alert dialog builder.
157         val alertDialog = dialogBuilder.create()
158
159         // Get a handle for the shared preferences.
160         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
161
162         // Get the screenshot preference.
163         val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
164
165         // Disable screenshots if not allowed.
166         if (!allowScreenshots) {
167             // Disable screenshots.
168             alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
169         }
170
171         //The alert dialog must be shown before the contents can be modified.
172         alertDialog.show()
173
174         // Instantiate a history array adapter.
175         val historyArrayAdapter = HistoryArrayAdapter(requireContext(), historyDataClassArrayList, currentPageId)
176
177         // Get a handle for the list view.
178         val listView = alertDialog.findViewById<ListView>(R.id.history_listview)!!
179
180         // Set the list view adapter.
181         listView.adapter = historyArrayAdapter
182
183         // Listen for clicks on entries in the list view.
184         listView.onItemClickListener = OnItemClickListener { _: AdapterView<*>?, view: View, _: Int, id: Long ->
185             // Convert the long ID to an int.
186             val itemId = id.toInt()
187
188             // Only consume the click if it is not on the current page ID.
189             if (itemId != currentPageId) {
190                 // Get a handle for the URL text view.
191                 val urlTextView = view.findViewById<TextView>(R.id.history_url_textview)
192
193                 // Get the URL.
194                 val url = urlTextView.text.toString()
195
196                 // Invoke the navigate history listener in the calling activity.  These commands cannot be run here because they need access to `applyDomainSettings()`.
197                 navigateHistoryListener.navigateHistory(url, currentPageId - itemId)
198
199                 // Dismiss the alert dialog.
200                 alertDialog.dismiss()
201             }
202         }
203
204         // Return the alert dialog.
205         return alertDialog
206     }
207 }