diff --git a/android/brave_java_resources.gni b/android/brave_java_resources.gni index 7a6acc1c4eb..7e67c57d376 100644 --- a/android/brave_java_resources.gni +++ b/android/brave_java_resources.gni @@ -414,6 +414,7 @@ brave_java_resources = [ "java/res/drawable/circle_shimmer.xml", "java/res/drawable/circular_progress.xml", "java/res/drawable/country_spinner_background.xml", + "java/res/drawable/create_custom_filter_edit_bg.xml", "java/res/drawable/crypto_wallet_blue_button.xml", "java/res/drawable/crypto_wallet_hollow_button.xml", "java/res/drawable/crypto_wallet_negative_button.xml", @@ -878,6 +879,7 @@ brave_java_resources = [ "java/res/layout/fragment_content_filtering.xml", "java/res/layout/fragment_create_account.xml", "java/res/layout/fragment_create_account.xml", + "java/res/layout/fragment_create_custom_filters.xml", "java/res/layout/fragment_cross_promotional_modal_dialog.xml", "java/res/layout/fragment_dapps_message.xml", "java/res/layout/fragment_dormant_users_engagement_dialog.xml", diff --git a/android/brave_java_sources.gni b/android/brave_java_sources.gni index 21134c873b7..44de53d2a59 100644 --- a/android/brave_java_sources.gni +++ b/android/brave_java_sources.gni @@ -399,6 +399,7 @@ brave_java_sources = [ "../../brave/android/java/org/chromium/chrome/browser/shields/BraveShieldsUtils.java", "../../brave/android/java/org/chromium/chrome/browser/shields/ContentFilteringAdapter.java", "../../brave/android/java/org/chromium/chrome/browser/shields/ContentFilteringFragment.java", + "../../brave/android/java/org/chromium/chrome/browser/shields/CreateCustomFiltersFragment.java", "../../brave/android/java/org/chromium/chrome/browser/shields/FilterListServiceFactory.java", "../../brave/android/java/org/chromium/chrome/browser/shields/UrlSanitizerServiceFactory.java", "../../brave/android/java/org/chromium/chrome/browser/signin/BraveSigninManager.java", diff --git a/android/java/org/chromium/chrome/browser/shields/BraveContentFilteringListener.java b/android/java/org/chromium/chrome/browser/shields/BraveContentFilteringListener.java index 2fc3690f39d..02e74f397f9 100644 --- a/android/java/org/chromium/chrome/browser/shields/BraveContentFilteringListener.java +++ b/android/java/org/chromium/chrome/browser/shields/BraveContentFilteringListener.java @@ -6,8 +6,13 @@ package org.chromium.chrome.browser.shields; public interface BraveContentFilteringListener { - public void onAddCustomFiltering(); - public void onCustomFilterToggle(int position, boolean isEnable); - public void onCustomFilterDelete(int position); - public void onDefaultFilterToggle(String uuid, boolean isEnable); + public void onAddSubscriptionFilter(); + + public void onSubscriptionFilterToggle(int position, boolean isEnable); + + public void onSubscriptionFilterDelete(int position); + + public void onFilterToggle(String uuid, boolean isEnable); + + public void onCustomFilters(); } diff --git a/android/java/org/chromium/chrome/browser/shields/ContentFilteringAdapter.java b/android/java/org/chromium/chrome/browser/shields/ContentFilteringAdapter.java index 5098e6d642a..d7b12a0403b 100644 --- a/android/java/org/chromium/chrome/browser/shields/ContentFilteringAdapter.java +++ b/android/java/org/chromium/chrome/browser/shields/ContentFilteringAdapter.java @@ -33,9 +33,10 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter mCustomFilterLists; + private ArrayList mSubscriptionFilterLists; private Value mFilterLists[]; private Context mContext; private boolean mIsEdit; @@ -63,8 +64,15 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter 0) { customFilterListViewHolder.titleText.setText(customFilter.title); @@ -132,11 +140,13 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter { - customFilter.enabled = !customFilter.enabled; - mBraveContentFileringListener.onCustomFilterToggle( - holder.getAdapterPosition() - ONE_ITEM_SPACE, customFilter.enabled); - }); + customFilterListViewHolder.toggleSwitch.setOnClickListener( + view -> { + customFilter.enabled = !customFilter.enabled; + mBraveContentFileringListener.onSubscriptionFilterToggle( + holder.getAdapterPosition() - TWO_ITEMS_SPACE, + customFilter.enabled); + }); if (mIsEdit) { customFilterListViewHolder.deleteImageView.setVisibility(View.VISIBLE); @@ -146,24 +156,29 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter { - if (mIsEdit) { - mBraveContentFileringListener.onCustomFilterDelete( - holder.getAdapterPosition() - ONE_ITEM_SPACE); - } - }); + customFilterListViewHolder.deleteImageView.setOnClickListener( + view -> { + if (mIsEdit) { + mBraveContentFileringListener.onSubscriptionFilterDelete( + holder.getAdapterPosition() - TWO_ITEMS_SPACE); + } + }); customFilterListViewHolder.urlText.setVisibility(View.VISIBLE); customFilterListViewHolder.arrowImageView.setVisibility(View.GONE); } - customFilterListViewHolder.itemView.setOnClickListener(view -> { - if (holder.getAdapterPosition() == mCustomFilterLists.size() + ONE_ITEM_SPACE) { - mBraveContentFileringListener.onAddCustomFiltering(); - } - }); + customFilterListViewHolder.itemView.setOnClickListener( + view -> { + if (holder.getAdapterPosition() == ONE_ITEM_SPACE) { + mBraveContentFileringListener.onCustomFilters(); + } else if (holder.getAdapterPosition() + == mSubscriptionFilterLists.size() + TWO_ITEMS_SPACE) { + mBraveContentFileringListener.onAddSubscriptionFilter(); + } + }); } else if (holder instanceof FilterListViewHolder) { FilterListViewHolder filterListViewHolder = (FilterListViewHolder) holder; - int filterPosition = position - mCustomFilterLists.size() - THREE_ITEMS_SPACE; + int filterPosition = position - mSubscriptionFilterLists.size() - FOUR_ITEMS_SPACE; if (filterPosition < mFilterLists.length) { Map storage = mFilterLists[filterPosition].getDictionaryValue().storage; @@ -175,17 +190,18 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter { - storage.get("enabled").setBoolValue(!isEnabled); - mBraveContentFileringListener.onDefaultFilterToggle(uuid, !isEnabled); - }); + filterListViewHolder.toggleSwitch.setOnClickListener( + view -> { + storage.get("enabled").setBoolValue(!isEnabled); + mBraveContentFileringListener.onFilterToggle(uuid, !isEnabled); + }); } } } @Override public int getItemCount() { - int count = mCustomFilterLists.size() + THREE_ITEMS_SPACE; + int count = mSubscriptionFilterLists.size() + FOUR_ITEMS_SPACE; if (mFilterLists != null) { count += mFilterLists.length; } @@ -214,9 +230,9 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter 0 && position <= mCustomFilterLists.size() + ONE_ITEM_SPACE) { + } else if (position > 0 && position <= mSubscriptionFilterLists.size() + TWO_ITEMS_SPACE) { return TYPE_CUSTOM_FILTER_LIST; } else { return TYPE_FILTER_LIST; @@ -225,21 +241,22 @@ public class ContentFilteringAdapter extends RecyclerView.Adapter customFilterLists) { - if (mCustomFilterLists != null && mCustomFilterLists.size() > 0) { - notifyItemRangeRemoved(ONE_ITEM_SPACE, mCustomFilterLists.size()); + public void setSubscriptionFilterLists(ArrayList customFilterLists) { + if (mSubscriptionFilterLists != null && mSubscriptionFilterLists.size() > 0) { + notifyItemRangeRemoved(TWO_ITEMS_SPACE, mSubscriptionFilterLists.size()); } - mCustomFilterLists = customFilterLists; - notifyItemRangeInserted(ONE_ITEM_SPACE, mCustomFilterLists.size()); + mSubscriptionFilterLists = customFilterLists; + notifyItemRangeInserted(TWO_ITEMS_SPACE, mSubscriptionFilterLists.size()); } public void setFilterLists(Value filterLists[]) { mFilterLists = filterLists; notifyItemRangeInserted( - mCustomFilterLists.size() + TWO_ITEMS_SPACE, mFilterLists.length + ONE_ITEM_SPACE); + mSubscriptionFilterLists.size() + THREE_ITEMS_SPACE, + mFilterLists.length + ONE_ITEM_SPACE); } public static class FilterListHeaderViewHolder extends RecyclerView.ViewHolder { diff --git a/android/java/org/chromium/chrome/browser/shields/ContentFilteringFragment.java b/android/java/org/chromium/chrome/browser/shields/ContentFilteringFragment.java index d4bbe2027e5..285bcfb57da 100644 --- a/android/java/org/chromium/chrome/browser/shields/ContentFilteringFragment.java +++ b/android/java/org/chromium/chrome/browser/shields/ContentFilteringFragment.java @@ -42,7 +42,7 @@ public class ContentFilteringFragment extends BravePreferenceFragment private ContentFilteringAdapter mAdapter; private FilterListAndroidHandler mFilterListAndroidHandler; - private ArrayList mCustomFilterLists; + private ArrayList mSubscriptionFilterLists; private Value mFilterLists[]; private MenuItem mEditItem; private MenuItem mDoneItem; @@ -71,13 +71,15 @@ public class ContentFilteringFragment extends BravePreferenceFragment public void onAttach(@NonNull Context context) { super.onAttach(context); - mAddCustomFilterResultLauncher = registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - ((BraveSettingsActivity) requireActivity()).getActivityResultRegistry(), result -> { - if (result.getResultCode() == Activity.RESULT_OK) { - getCustomFilterLists(); - } - }); + mAddCustomFilterResultLauncher = + registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + ((BraveSettingsActivity) requireActivity()).getActivityResultRegistry(), + result -> { + if (result.getResultCode() == Activity.RESULT_OK) { + getSubscriptionFilters(); + } + }); } private void setData() { @@ -88,20 +90,21 @@ public class ContentFilteringFragment extends BravePreferenceFragment mRecyclerView.setLayoutManager(linearLayoutManager); mAdapter = new ContentFilteringAdapter(getActivity(), this); mRecyclerView.setAdapter(mAdapter); - getCustomFilterLists(); + getSubscriptionFilters(); getFilterLists(); } - private void getCustomFilterLists() { + private void getSubscriptionFilters() { if (mFilterListAndroidHandler != null) { - mFilterListAndroidHandler.getSubscriptions(subscriptions -> { - mCustomFilterLists = new ArrayList(Arrays.asList(subscriptions)); - mAdapter.setCustomFilterLists(mCustomFilterLists); - mIsGetSubscriptionsLoaded = true; - if (mIsMenuLoaded) { - checkForEmptyCustomFilterLists(true); - } - }); + mFilterListAndroidHandler.getSubscriptions( + subscriptions -> { + mSubscriptionFilterLists = new ArrayList(Arrays.asList(subscriptions)); + mAdapter.setSubscriptionFilterLists(mSubscriptionFilterLists); + mIsGetSubscriptionsLoaded = true; + if (mIsMenuLoaded) { + checkForEmptySubscriptionFilters(true); + } + }); } } @@ -115,17 +118,17 @@ public class ContentFilteringFragment extends BravePreferenceFragment } @Override - public void onCustomFilterToggle(int position, boolean isEnable) { + public void onSubscriptionFilterToggle(int position, boolean isEnable) { if (mFilterListAndroidHandler != null) { - SubscriptionInfo customFilter = mCustomFilterLists.get(position); + SubscriptionInfo customFilter = mSubscriptionFilterLists.get(position); mFilterListAndroidHandler.enableSubscription(customFilter.subscriptionUrl, isEnable); customFilter.enabled = isEnable; } } @Override - public void onAddCustomFiltering() { - if (mCustomFilterLists.size() > 0) { + public void onAddSubscriptionFilter() { + if (mSubscriptionFilterLists.size() > 0) { isEditSelected(false); } Intent intent = mSettingsLauncher.createSettingsActivityIntent( @@ -134,26 +137,37 @@ public class ContentFilteringFragment extends BravePreferenceFragment } @Override - public void onCustomFilterDelete(int position) { + public void onSubscriptionFilterDelete(int position) { if (mFilterListAndroidHandler != null) { - SubscriptionInfo customFilter = mCustomFilterLists.get(position); + SubscriptionInfo customFilter = mSubscriptionFilterLists.get(position); mFilterListAndroidHandler.deleteSubscription(customFilter.subscriptionUrl); - mCustomFilterLists.remove(position); + mSubscriptionFilterLists.remove(position); mAdapter.notifyItemRemoved(position + 1); mAdapter.notifyItemRangeChanged(position + 1, mAdapter.getItemCount()); - checkForEmptyCustomFilterLists(false); + checkForEmptySubscriptionFilters(false); } } @Override - public void onDefaultFilterToggle(String uuid, boolean isEnable) { + public void onCustomFilters() { + if (mSubscriptionFilterLists.size() > 0) { + isEditSelected(false); + } + Intent intent = + mSettingsLauncher.createSettingsActivityIntent( + getActivity(), CreateCustomFiltersFragment.class.getName(), null); + getActivity().startActivity(intent); + } + + @Override + public void onFilterToggle(String uuid, boolean isEnable) { if (mFilterListAndroidHandler != null) { mFilterListAndroidHandler.enableFilter(uuid, isEnable); } } - private void checkForEmptyCustomFilterLists(boolean shouldEditVisible) { - if (mCustomFilterLists.size() == 0) { + private void checkForEmptySubscriptionFilters(boolean shouldEditVisible) { + if (mSubscriptionFilterLists.size() == 0) { isEditSelected(false); mEditItem.setVisible(false); } else if (shouldEditVisible) { @@ -192,7 +206,7 @@ public class ContentFilteringFragment extends BravePreferenceFragment mDoneItem = menu.findItem(R.id.menu_id_done); mIsMenuLoaded = true; if (mIsGetSubscriptionsLoaded) { - checkForEmptyCustomFilterLists(true); + checkForEmptySubscriptionFilters(true); } } diff --git a/android/java/org/chromium/chrome/browser/shields/CreateCustomFiltersFragment.java b/android/java/org/chromium/chrome/browser/shields/CreateCustomFiltersFragment.java new file mode 100644 index 00000000000..88168786246 --- /dev/null +++ b/android/java/org/chromium/chrome/browser/shields/CreateCustomFiltersFragment.java @@ -0,0 +1,151 @@ +/* Copyright (c) 2023 The Brave Authors. All rights reserved. + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at https://mozilla.org/MPL/2.0/. */ + +package org.chromium.chrome.browser.shields; + +import android.os.Bundle; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import org.chromium.brave_shields.mojom.FilterListAndroidHandler; +import org.chromium.chrome.R; +import org.chromium.chrome.browser.BraveRewardsHelper; +import org.chromium.chrome.browser.customtabs.CustomTabActivity; +import org.chromium.chrome.browser.settings.BravePreferenceFragment; +import org.chromium.mojo.bindings.ConnectionErrorHandler; +import org.chromium.mojo.system.MojoException; +import org.chromium.ui.text.NoUnderlineClickableSpan; +import org.chromium.ui.widget.Toast; + +public class CreateCustomFiltersFragment extends BravePreferenceFragment + implements ConnectionErrorHandler { + public static final String BRAVE_ADBLOCK_FILTER_SYNTAX_PAGE = + "https://support.brave.com/hc/en-us/articles/6449369961741"; + + private FilterListAndroidHandler mFilterListAndroidHandler; + private EditText mEtCustomFilters; + + @Override + public View onCreateView( + LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_create_custom_filters, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + if (getActivity() != null) { + getActivity().setTitle(R.string.create_custom_filters_title); + } + super.onActivityCreated(savedInstanceState); + + setData(); + } + + private void setData() { + initFilterListAndroidHandler(); + mEtCustomFilters = getView().findViewById(R.id.enter_custom_filters); + TextView tvSummary = getView().findViewById(R.id.summary); + String summaryText = + String.format( + getResources().getString(R.string.create_custom_filter_summary), + getResources().getString(R.string.adblock_filter_syntax)); + Spanned summaryTextSpanned = BraveRewardsHelper.spannedFromHtmlString(summaryText); + SpannableString summaryTextSpannableString = + new SpannableString(summaryTextSpanned.toString()); + + if (getActivity() != null) { + NoUnderlineClickableSpan summaryTextClickableSpan = + new NoUnderlineClickableSpan( + getActivity(), + R.color.brave_link, + (textView) -> { + CustomTabActivity.showInfoPage( + getActivity(), BRAVE_ADBLOCK_FILTER_SYNTAX_PAGE); + }); + + BraveRewardsHelper.setSpan( + getActivity(), + summaryText, + summaryTextSpannableString, + R.string.adblock_filter_syntax, + summaryTextClickableSpan); + tvSummary.setMovementMethod(LinkMovementMethod.getInstance()); + tvSummary.setText(summaryTextSpannableString); + } + + Button saveBtn = getView().findViewById(R.id.btn_save); + saveBtn.setOnClickListener( + view -> { + updateCustomFilters(); + }); + getCustomFilters(); + } + + @Override + public void onConnectionError(MojoException e) { + mFilterListAndroidHandler = null; + initFilterListAndroidHandler(); + } + + private void initFilterListAndroidHandler() { + if (mFilterListAndroidHandler != null) { + return; + } + + mFilterListAndroidHandler = + FilterListServiceFactory.getInstance().getFilterListAndroidHandler(this); + } + + private void getCustomFilters() { + if (mFilterListAndroidHandler != null) { + mFilterListAndroidHandler.getCustomFilters( + customFilters -> { + mEtCustomFilters.setText(customFilters); + }); + } + } + + private void updateCustomFilters() { + if (mFilterListAndroidHandler != null) { + mFilterListAndroidHandler.updateCustomFilters( + mEtCustomFilters.getText().toString(), + isUpdated -> { + int messageId = + isUpdated + ? R.string.saved_changes_success + : R.string.brave_rewards_local_general_grant_error_title; + if (getActivity() != null) { + Toast.makeText(getActivity(), messageId, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + MenuItem closeItem = menu.findItem(R.id.close_menu_id); + if (closeItem != null) { + closeItem.setVisible(false); + } + } + + @Override + public void onDestroy() { + if (mFilterListAndroidHandler != null) { + mFilterListAndroidHandler.close(); + } + super.onDestroy(); + } +} diff --git a/android/java/res/drawable/create_custom_filter_edit_bg.xml b/android/java/res/drawable/create_custom_filter_edit_bg.xml new file mode 100644 index 00000000000..051fd35fa5e --- /dev/null +++ b/android/java/res/drawable/create_custom_filter_edit_bg.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/android/java/res/layout/fragment_create_custom_filters.xml b/android/java/res/layout/fragment_create_custom_filters.xml new file mode 100644 index 00000000000..f839ed0782e --- /dev/null +++ b/android/java/res/layout/fragment_create_custom_filters.xml @@ -0,0 +1,57 @@ + + + + + + + + +