From: Soren Stoutner Date: Wed, 9 Nov 2016 18:07:32 +0000 (-0700) Subject: Add a forward and back history list. Resolves https://redmine.stoutner.com/issues/24. X-Git-Tag: v1.12~2 X-Git-Url: https://gitweb.stoutner.com/?a=commitdiff_plain;h=eb1e349d876e09e2b82e4eb9d6dc199147e1cde5;p=PrivacyBrowserAndroid.git Add a forward and back history list. Resolves https://redmine.stoutner.com/issues/24. --- diff --git a/.idea/misc.xml b/.idea/misc.xml index 95f0f031..1caa1363 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/src/main/assets/de/about_licenses.html b/app/src/main/assets/de/about_licenses.html index 0ca96583..b09cce63 100644 --- a/app/src/main/assets/de/about_licenses.html +++ b/app/src/main/assets/de/about_licenses.html @@ -72,6 +72,8 @@

ic_bookmark_border.

+

ic_close.

+

ic_create_new_folder.

ic_download.

@@ -80,6 +82,10 @@

ic_exit_to_app.

+

ic_expand_less.

+ +

ic_expand_more.

+

ic_file_download.

ic_folder.

@@ -94,6 +100,8 @@

ic_language.

+

ic_list.

+

ic_select_all.

ic_settings.

@@ -106,12 +114,6 @@

ic_web.

-

ic_expand_less.

- -

ic_expand_more.

- -

ic_close.

-

Cookie wurde von Google erstellt. diff --git a/app/src/main/assets/en/about_licenses.html b/app/src/main/assets/en/about_licenses.html index 3ee97602..13edb7ea 100644 --- a/app/src/main/assets/en/about_licenses.html +++ b/app/src/main/assets/en/about_licenses.html @@ -69,6 +69,8 @@

ic_bookmark_border.

+

ic_close.

+

ic_create_new_folder.

ic_download.

@@ -77,6 +79,10 @@

ic_exit_to_app.

+

ic_expand_less.

+ +

ic_expand_more.

+

ic_file_download.

ic_folder.

@@ -91,6 +97,8 @@

ic_language.

+

ic_list.

+

ic_select_all.

ic_settings.

@@ -103,12 +111,6 @@

ic_web.

-

ic_expand_less.

- -

ic_expand_more.

- -

ic_close.

-

cookie was created by Google. diff --git a/app/src/main/assets/en/images/ic_list.png b/app/src/main/assets/en/images/ic_list.png new file mode 100644 index 00000000..786df41d Binary files /dev/null and b/app/src/main/assets/en/images/ic_list.png differ diff --git a/app/src/main/java/com/stoutner/privacybrowser/DownloadFile.java b/app/src/main/java/com/stoutner/privacybrowser/DownloadFile.java index 8e04cf64..1a68f71f 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/DownloadFile.java +++ b/app/src/main/java/com/stoutner/privacybrowser/DownloadFile.java @@ -101,10 +101,11 @@ public class DownloadFile extends AppCompatDialogFragment { // `downloadFileListener` is used in `onAttach()` and `onCreateDialog()`. private DownloadFileListener downloadFileListener; - // Check to make sure tha the parent activity implements the listener. @Override public void onAttach(Context context) { super.onAttach(context); + + // Check to make sure the parent activity implements the listener. try { downloadFileListener = (DownloadFileListener) context; } catch (ClassCastException exception) { @@ -112,25 +113,28 @@ public class DownloadFile extends AppCompatDialogFragment { } } - // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. - @SuppressLint("InflateParams") @Override @NonNull + // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. + @SuppressLint("InflateParams") public Dialog onCreateDialog(Bundle savedInstanceState) { // Get the activity's layout inflater. LayoutInflater layoutInflater = getActivity().getLayoutInflater(); // Use `AlertDialog.Builder` to create the `AlertDialog`. `R.style.lightAlertDialog` formats the color of the button text. AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.LightAlertDialog); + + // Set the title. dialogBuilder.setTitle(R.string.save_as); - // The parent view is `null` because it will be assigned by `AlertDialog`. + + // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`. dialogBuilder.setView(layoutInflater.inflate(R.layout.download_file_dialog, null)); // Set an `onClick()` listener on the negative button. dialogBuilder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - // Do nothing if `Cancel` is clicked. + // Do nothing if `Cancel` is clicked. The `Dialog` will automatically close. } }); @@ -143,7 +147,6 @@ public class DownloadFile extends AppCompatDialogFragment { } }); - // Create an `AlertDialog` from the `AlertDialog.Builder`. final AlertDialog alertDialog = dialogBuilder.create(); @@ -184,7 +187,6 @@ public class DownloadFile extends AppCompatDialogFragment { } }); - // `onCreateDialog` requires the return of an `AlertDialog`. return alertDialog; } diff --git a/app/src/main/java/com/stoutner/privacybrowser/History.java b/app/src/main/java/com/stoutner/privacybrowser/History.java new file mode 100644 index 00000000..0548c2b5 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/History.java @@ -0,0 +1,35 @@ +/** + * Copyright 2016 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 . + */ + +package com.stoutner.privacybrowser; + +import android.graphics.Bitmap; + +// Create a `History` object. +class History { + // Create the `History` package-local variables. + Bitmap entryFavoriteIcon; + String entryUrl; + + History(Bitmap entryFavoriteIcon, String entryUrl){ + // Populate the package-local variables. + this.entryFavoriteIcon = entryFavoriteIcon; + this.entryUrl = entryUrl; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/HistoryArrayAdapter.java b/app/src/main/java/com/stoutner/privacybrowser/HistoryArrayAdapter.java new file mode 100644 index 00000000..414f5fc4 --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/HistoryArrayAdapter.java @@ -0,0 +1,80 @@ +/** + * Copyright 2016 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 . + */ + +package com.stoutner.privacybrowser; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import java.util.ArrayList; + +class HistoryArrayAdapter extends ArrayAdapter { + + // `currentPage` is used in `HistoryArrayAdapter` and `getView()`. + private int currentPage; + + HistoryArrayAdapter(Context context, ArrayList historyArrayList, int currentPageId) { + // We need to call `super` from the base `ArrayAdapter`. `0` is the `textViewResourceId`. + super(context, 0, historyArrayList); + + // Store `currentPageId` in the class variable. + currentPage = currentPageId; + } + + @Override + @NonNull + public View getView(int position, View convertView, @NonNull ViewGroup parent) { + // Inflate the view if it is `null`. + if (convertView == null) { + // `false` does not attach `url_history_item_linearlayout` to `parent`. + convertView = LayoutInflater.from(getContext()).inflate(R.layout.url_history_item_linearlayout, parent, false); + } + + // Get handles for `favoriteIconImageView` and `urlTextView`. + ImageView favoriteIconImageView = (ImageView) convertView.findViewById(R.id.history_favorite_icon_imageview); + TextView urlTextView = (TextView) convertView.findViewById(R.id.history_url_textview); + + // Get the URL history for this position. + History history = getItem(position); + + // Remove the lint warning below that `history` might be `null`. + assert history != null; + + // Set `favoriteIconImageView` and `urlTextView`. + favoriteIconImageView.setImageBitmap(history.entryFavoriteIcon); + urlTextView.setText(history.entryUrl); + + // Set the URL text for `currentPage` to be grey. + if (position == currentPage) { + urlTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.grey_500)); + } else { + urlTextView.setTextColor(ContextCompat.getColor(getContext(), R.color.black)); + } + + // Return the modified `convertView`. + return convertView; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java index 69ac5441..779d2d69 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java +++ b/app/src/main/java/com/stoutner/privacybrowser/MainWebViewActivity.java @@ -62,6 +62,7 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.CookieManager; import android.webkit.DownloadListener; import android.webkit.SslErrorHandler; +import android.webkit.WebBackForwardList; import android.webkit.WebChromeClient; import android.webkit.WebStorage; import android.webkit.WebView; @@ -84,7 +85,7 @@ import java.util.Map; // We need to use AppCompatActivity from android.support.v7.app.AppCompatActivity to have access to the SupportActionBar until the minimum API is >= 21. public class MainWebViewActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, CreateHomeScreenShortcut.CreateHomeScreenSchortcutListener, - SslCertificateError.SslCertificateErrorListener, DownloadFile.DownloadFileListener, DownloadImage.DownloadImageListener { + SslCertificateError.SslCertificateErrorListener, DownloadFile.DownloadFileListener, DownloadImage.DownloadImageListener, UrlHistory.UrlHistoryListener { // `appBar` is public static so it can be accessed from `OrbotProxyHelper`. // It is also used in `onCreate()`, `onOptionsItemSelected()`, and `closeFindOnPage()`. @@ -294,6 +295,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation final Menu navigationMenu = navigationView.getMenu(); final MenuItem navigationBackMenuItem = navigationMenu.getItem(1); final MenuItem navigationForwardMenuItem = navigationMenu.getItem(2); + final MenuItem navigationHistoryMenuItem = navigationMenu.getItem(3); // The `DrawerListener` allows us to update the Navigation Menu. drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() { @@ -311,9 +313,10 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation @Override public void onDrawerStateChanged(int newState) { - // Update the back and forward menu items every time the drawer opens. + // Update the `Back`, `Forward`, and `History` menu items every time the drawer opens. navigationBackMenuItem.setEnabled(mainWebView.canGoBack()); navigationForwardMenuItem.setEnabled(mainWebView.canGoForward()); + navigationHistoryMenuItem.setEnabled((mainWebView.canGoBack() || mainWebView.canGoForward())); // Hide the keyboard so we can see the navigation menu. `0` indicates no additional flags. inputMethodManager.hideSoftInputFromWindow(mainWebView.getWindowToken(), 0); @@ -878,7 +881,7 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation return true; case R.id.addToHomescreen: - // Show the `CreateHomeScreenShortcut` `AlertDialog` and name this instance `@string/create_shortcut`. + // Show the `CreateHomeScreenShortcut` `AlertDialog` and name this instance `R.string.create_shortcut`. AppCompatDialogFragment createHomeScreenShortcutDialogFragment = new CreateHomeScreenShortcut(); createHomeScreenShortcutDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.create_shortcut)); @@ -929,6 +932,15 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation } break; + case R.id.history: + // Gte the `WebBackForwardList`. + WebBackForwardList webBackForwardList = mainWebView.copyBackForwardList(); + + // Show the `UrlHistory` `AlertDialog` and name this instance `R.string.history`. `this` is the `Context`. + AppCompatDialogFragment urlHistoryDialogFragment = UrlHistory.loadBackForwardList(this, webBackForwardList); + urlHistoryDialogFragment.show(getSupportFragmentManager(), getResources().getString(R.string.history)); + break; + case R.id.bookmarks: // Launch BookmarksActivity. Intent bookmarksIntent = new Intent(this, BookmarksActivity.class); @@ -1270,6 +1282,12 @@ public class MainWebViewActivity extends AppCompatActivity implements Navigation sslErrorHandler.proceed(); } + @Override + public void onUrlHistoryEntrySelected(int moveBackOrForwardSteps) { + // Load the history entry. + mainWebView.goBackOrForward(moveBackOrForwardSteps); + } + // Override onBackPressed to handle the navigation drawer and mainWebView. @Override public void onBackPressed() { diff --git a/app/src/main/java/com/stoutner/privacybrowser/UrlHistory.java b/app/src/main/java/com/stoutner/privacybrowser/UrlHistory.java new file mode 100644 index 00000000..d2d4fecd --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/UrlHistory.java @@ -0,0 +1,240 @@ +/** + * Copyright 2016 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 . + */ + +package com.stoutner.privacybrowser; + +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +// `android.support.v7.app.AlertDialog` uses more of the horizontal screen real estate versus `android.app.AlertDialog's` smaller width. +import android.support.annotation.NonNull; +import android.support.v4.content.ContextCompat; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatDialogFragment; +import android.util.Base64; +import android.view.LayoutInflater; +import android.view.View; +import android.webkit.WebBackForwardList; +import android.widget.AdapterView; +import android.widget.ListView; + +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; + +public class UrlHistory extends AppCompatDialogFragment{ + + // `historyArrayList` and `currentPageId` pass information from `onCreate()` to `onCreateDialog()`. + private ArrayList historyArrayList = new ArrayList<>(); + private int currentPageId; + + public static UrlHistory loadBackForwardList(Context context, WebBackForwardList webBackForwardList) { + // Create `argumentsBundle`. + Bundle argumentsBundle = new Bundle(); + + // Store `currentPageIndex`. + int currentPageIndex = webBackForwardList.getCurrentIndex(); + + // Setup `urlArrayList` and `iconArrayList`. + ArrayList urlArrayList = new ArrayList<>(); + ArrayList iconBase64StringArrayList = new ArrayList<>(); + + // Get the default favorite icon `Drawable`. + Drawable defaultFavoriteIconDrawable = ContextCompat.getDrawable(context, R.drawable.world); + + // Convert `defaultFavoriteIconDrawable` to a `BitmapDrawable`. + BitmapDrawable defaultFavoriteIconBitmapDrawable = (BitmapDrawable) defaultFavoriteIconDrawable; + + // Extract a `Bitmap` from `defaultFavoriteIconBitmapDrawable`. + Bitmap defaultFavoriteIcon = defaultFavoriteIconBitmapDrawable.getBitmap(); + + // Populate `urlArrayList` and `iconArrayList` 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`. + Bitmap iconBitmap; + + // 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; + } else { // Get the icon from `webBackForwardList`. + iconBitmap = webBackForwardList.getItemAtIndex(i).getFavicon(); + } + + // Create a `ByteArrayOutputStream`. + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + + // Convert the favorite icon `Bitmap` to a `ByteArrayOutputStream`. `100` is the compression quality, which is ignored by `PNG`. + iconBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); + + // Convert the favorite icon `ByteArrayOutputStream` to a `byte[]`. + byte[] byteArray = byteArrayOutputStream.toByteArray(); + + // Encode the favorite icon `byte[]` as a Base64 `String`. + String iconBase64String = Base64.encodeToString(byteArray, Base64.DEFAULT); + + // Store the favorite icon Base64 `String` in `iconBase64StringArrayList`. + iconBase64StringArrayList.add(iconBase64String); + } + + // Store the variables in the `Bundle`. + argumentsBundle.putInt("Current_Page", currentPageIndex); + argumentsBundle.putStringArrayList("URL_History", urlArrayList); + argumentsBundle.putStringArrayList("Favorite_Icons", iconBase64StringArrayList); + + // Add `argumentsBundle` to this instance of `UrlHistory`. + UrlHistory thisUrlHistoryDialog = new UrlHistory(); + thisUrlHistoryDialog.setArguments(argumentsBundle); + return thisUrlHistoryDialog; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Get the `ArrayLists` from the `Arguments`. + ArrayList urlStringArrayList = getArguments().getStringArrayList("URL_History"); + ArrayList favoriteIconBase64StringArrayList = getArguments().getStringArrayList("Favorite_Icons"); + + // Remove the lint warning below that the `ArrayLists` might be `null`. + assert urlStringArrayList != null; + assert favoriteIconBase64StringArrayList != null; + + // Populate `historyArrayList`. We go down from `urlStringArrayList.size()` so that the newest entries are at the top. `-1` is needed because `historyArrayList` is zero-based. + for (int i=urlStringArrayList.size() -1; i >= 0; i--) { + // Decode the favorite icon Base64 `String` to a `byte[]`. + byte[] favoriteIconByteArray = Base64.decode(favoriteIconBase64StringArrayList.get(i), Base64.DEFAULT); + + // Convert the favorite icon `byte[]` to a `Bitmap`. `0` is the starting offset. + Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length); + + // Store the favorite icon and the URL in `historyEntry`. + History historyEntry = new History(favoriteIconBitmap, urlStringArrayList.get(i)); + + // Add this history entry to `historyArrayList`. + historyArrayList.add(historyEntry); + } + + // Get the original current page ID. + int originalCurrentPageId = getArguments().getInt("Current_Page"); + + // Subtract `originalCurrentPageId` from the array size because we reversed the order of the array so that the newest entries are at the top. `-1` is needed because the array is zero-based. + currentPageId = urlStringArrayList.size() - 1 - originalCurrentPageId; + } + + // The public interface is used to send information back to the parent activity. + public interface UrlHistoryListener { + // Send back the number of steps to move forward or back. + void onUrlHistoryEntrySelected(int moveBackOrForwardSteps); + } + + // `urlHistoryListener` is used in `onAttach()` and `onCreateDialog()`. + private UrlHistoryListener urlHistoryListener; + + @Override + public void onAttach(Context context) { + super.onAttach(context); + + // Check to make sure tha the parent activity implements the listener. + try { + urlHistoryListener = (UrlHistoryListener) context; + } catch (ClassCastException exception) { + throw new ClassCastException(context.toString() + " must implement UrlHistoryListener."); + } + } + + @Override + @NonNull + // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`. + @SuppressLint("InflateParams") + public Dialog onCreateDialog(Bundle savedInstanceState) { + // Get the activity's layout inflater. + LayoutInflater layoutInflater = getActivity().getLayoutInflater(); + + // Use `AlertDialog.Builder` to create the `AlertDialog`. `R.style.lightAlertDialog` formats the color of the button text. + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.LightAlertDialog); + + // Set the title. + dialogBuilder.setTitle(R.string.history); + + // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`. + dialogBuilder.setView(layoutInflater.inflate(R.layout.url_history_dialog, null)); + + // Set an `onClick()` listener on the negative button. + dialogBuilder.setNegativeButton(R.string.close, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Do nothing if `Close` is clicked. The `Dialog` will automatically close. + } + }); + + // Create an `AlertDialog` from the `AlertDialog.Builder`. + final AlertDialog alertDialog = dialogBuilder.create(); + + // We need to show `alertDialog` before we can modify the contents. + alertDialog.show(); + + // Instantiate a `HistoryArrayAdapter`. + final HistoryArrayAdapter historyArrayAdapter = new HistoryArrayAdapter(getContext(), historyArrayList, currentPageId); + + // Get a handle for `listView`. + ListView listView = (ListView) alertDialog.findViewById(R.id.history_listview); + + // Remove the warning below that `listView` might be `null`. + assert listView != null; + + // Set the adapter on `listView`. + listView.setAdapter(historyArrayAdapter); + + // Listen for clicks on entries in `listView`. + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + // Convert the `long` `id` to an `int`. + int itemId = (int) id; + + // Only enable the click if it is not on the `currentPageId`. + if (itemId != currentPageId) { + // Get the history entry for this `itemId`. + History historyEntry = historyArrayAdapter.getItem(itemId); + + // Remove the lint warning below that `historyEntry` might be `null`. + assert historyEntry != null; + + // Send the history entry URL to be loaded in `mainWebView`. + urlHistoryListener.onUrlHistoryEntrySelected(currentPageId - itemId); + + // Dismiss the `Dialog`. + alertDialog.dismiss(); + } + } + }); + + // `onCreateDialog` requires the return of an `AlertDialog`. + return alertDialog; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/history.xml b/app/src/main/res/drawable/history.xml new file mode 100644 index 00000000..83e95cb4 --- /dev/null +++ b/app/src/main/res/drawable/history.xml @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/app/src/main/res/layout/url_history_dialog.xml b/app/src/main/res/layout/url_history_dialog.xml new file mode 100644 index 00000000..0a32dfcb --- /dev/null +++ b/app/src/main/res/layout/url_history_dialog.xml @@ -0,0 +1,25 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/url_history_item_linearlayout.xml b/app/src/main/res/layout/url_history_item_linearlayout.xml new file mode 100644 index 00000000..bcd02ae1 --- /dev/null +++ b/app/src/main/res/layout/url_history_item_linearlayout.xml @@ -0,0 +1,47 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/webview_navigation_menu.xml b/app/src/main/res/menu/webview_navigation_menu.xml index 756013c3..de2c0a5d 100644 --- a/app/src/main/res/menu/webview_navigation_menu.xml +++ b/app/src/main/res/menu/webview_navigation_menu.xml @@ -38,6 +38,12 @@ android:icon="@drawable/forward" android:orderInCategory="30" /> + + @@ -45,13 +51,13 @@ android:id="@+id/bookmarks" android:title="@string/bookmarks" android:icon="@drawable/bookmarks" - android:orderInCategory="40" /> + android:orderInCategory="50" /> + android:orderInCategory="60" /> + android:orderInCategory="70" /> + android:orderInCategory="80" /> + android:orderInCategory="90" /> @@ -82,6 +88,6 @@ android:id="@+id/clearAndExit" android:title="@string/clear_and_exit" android:icon="@drawable/exit" - android:orderInCategory="90" /> + android:orderInCategory="100" /> \ No newline at end of file diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f9560d07..5ba95cf3 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -91,6 +91,7 @@ Startseite Zurück Vorwärts + Verlauf Lesezeichen Downloads Einstellungen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f92bd839..26f41f3b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -90,6 +90,7 @@ Home Back Forward + History Bookmarks Downloads Settings