From 01e53f8e48de91e00485c15b60afde063226e0cc Mon Sep 17 00:00:00 2001 From: stom79 Date: Wed, 26 Sep 2018 18:30:08 +0200 Subject: [PATCH] Blocked domains --- .../mastodon/activities/BaseMainActivity.java | 7 + .../asynctasks/RetrieveDomainsAsyncTask.java | 58 +++++ .../fr/gouv/etalab/mastodon/client/API.java | 106 +++++++++ .../etalab/mastodon/client/APIResponse.java | 9 + .../mastodon/drawers/DomainsListAdapter.java | 126 +++++++++++ .../DisplayMutedInstanceFragment.java | 205 ++++++++++++++++++ .../OnRetrieveDomainsInterface.java | 26 +++ app/src/main/res/layout/drawer_domain.xml | 45 ++++ .../res/layout/fragment_muted_instances.xml | 82 +++++++ .../main/res/menu/activity_main_drawer.xml | 4 + app/src/main/res/values/strings.xml | 4 + 11 files changed, 672 insertions(+) create mode 100644 app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveDomainsAsyncTask.java create mode 100644 app/src/main/java/fr/gouv/etalab/mastodon/drawers/DomainsListAdapter.java create mode 100644 app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayMutedInstanceFragment.java create mode 100644 app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveDomainsInterface.java create mode 100644 app/src/main/res/layout/drawer_domain.xml create mode 100644 app/src/main/res/layout/fragment_muted_instances.xml diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java index b9ff9768e..10cbdae9b 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/activities/BaseMainActivity.java @@ -97,6 +97,7 @@ import fr.gouv.etalab.mastodon.fragments.DisplayDraftsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayFiltersFragment; import fr.gouv.etalab.mastodon.fragments.DisplayFollowRequestSentFragment; import fr.gouv.etalab.mastodon.fragments.DisplayListsFragment; +import fr.gouv.etalab.mastodon.fragments.DisplayMutedInstanceFragment; import fr.gouv.etalab.mastodon.fragments.DisplayNotificationsFragment; import fr.gouv.etalab.mastodon.fragments.DisplayScheduledTootsFragment; import fr.gouv.etalab.mastodon.fragments.DisplaySearchFragment; @@ -1487,6 +1488,12 @@ public abstract class BaseMainActivity extends BaseActivity fragmentTag = "BLOCKS"; fragmentManager.beginTransaction() .replace(R.id.main_app_container, accountsFragment, fragmentTag).commit(); + }else if (id == R.id.nav_blocked_domains) { + toot.hide(); + DisplayMutedInstanceFragment displayMutedInstanceFragment = new DisplayMutedInstanceFragment(); + fragmentTag = "BLOCKED_DOMAINS"; + fragmentManager.beginTransaction() + .replace(R.id.main_app_container, displayMutedInstanceFragment, fragmentTag).commit(); }else if (id == R.id.nav_muted) { toot.hide(); accountsFragment = new DisplayAccountsFragment(); diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveDomainsAsyncTask.java b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveDomainsAsyncTask.java new file mode 100644 index 000000000..823a93625 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/asynctasks/RetrieveDomainsAsyncTask.java @@ -0,0 +1,58 @@ +/* Copyright 2018 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program 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. + * + * Mastalab 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 Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.asynctasks; + +import android.content.Context; +import android.os.AsyncTask; + +import java.lang.ref.WeakReference; + +import fr.gouv.etalab.mastodon.client.API; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveDomainsInterface; + + +/** + * Created by Thomas on 26/09/2018. + * Retrieves blocked instance + */ + +public class RetrieveDomainsAsyncTask extends AsyncTask { + + + private OnRetrieveDomainsInterface listener; + private WeakReference contextReference; + private APIResponse apiResponse; + private String max_id; + + public RetrieveDomainsAsyncTask(Context context, String max_id, OnRetrieveDomainsInterface onRetrieveDomainsInterface){ + this.contextReference = new WeakReference<>(context); + this.listener = onRetrieveDomainsInterface; + this.max_id = max_id; + } + + @Override + protected Void doInBackground(Void... params) { + API api = new API(this.contextReference.get()); + apiResponse = api.getBlockedDomain(max_id); + return null; + } + + @Override + protected void onPostExecute(Void result) { + listener.onRetrieveDomains(apiResponse); + } + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java index 73f6f925c..0361d5501 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/API.java @@ -64,6 +64,7 @@ public class API { private String prefKeyOauthTokenT; private APIResponse apiResponse; private Error APIError; + private List domains; public enum StatusAction{ FAVOURITE, @@ -775,6 +776,95 @@ public class API { } + + /** + * Retrieves blocked domains for the authenticated account *synchronously* + * @param max_id String id max + * @return APIResponse + */ + @SuppressWarnings("SameParameterValue") + public APIResponse getBlockedDomain(String max_id){ + + HashMap params = new HashMap<>(); + if( max_id != null ) + params.put("max_id", max_id); + params.put("limit","80"); + domains = new ArrayList<>(); + try { + HttpsConnection httpsConnection = new HttpsConnection(context); + String response = httpsConnection.get(getAbsoluteUrl("/domain_blocks"), 60, params, prefKeyOauthTokenT); + apiResponse.setSince_id(httpsConnection.getSince_id()); + apiResponse.setMax_id(httpsConnection.getMax_id()); + domains = parseDomains(new JSONArray(response)); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); + } + apiResponse.setDomains(domains); + return apiResponse; + } + + /** + * Add a blocked domains for the authenticated account *synchronously* + * @param domain String domain name + */ + @SuppressWarnings("SameParameterValue") + public int addBlockedDomain(String domain){ + + HashMap params = new HashMap<>(); + params.put("domain",domain); + domains = new ArrayList<>(); + HttpsConnection httpsConnection; + try { + httpsConnection = new HttpsConnection(context); + httpsConnection.post(getAbsoluteUrl("/domain_blocks"), 60, params, prefKeyOauthTokenT); + actionCode = httpsConnection.getActionCode(); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } + return actionCode; + } + + /** + * Delete a blocked domains for the authenticated account *synchronously* + * @param domain String domain name + */ + @SuppressWarnings("SameParameterValue") + public int deleteBlockedDomain(String domain){ + + HashMap params = new HashMap<>(); + params.put("domain",domain); + domains = new ArrayList<>(); + HttpsConnection httpsConnection; + try { + httpsConnection = new HttpsConnection(context); + httpsConnection.delete(getAbsoluteUrl("/domain_blocks"), 60, params, prefKeyOauthTokenT); + actionCode = httpsConnection.getActionCode(); + } catch (HttpsConnection.HttpsConnectionException e) { + setError(e.getStatusCode(), e); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (KeyManagementException e) { + e.printStackTrace(); + } + return actionCode; + } + /** * Retrieves follow requests for the authenticated account *synchronously* * @param max_id String id max @@ -2033,6 +2123,22 @@ public class API { } + /** + * Parse Domains + * @param jsonArray JSONArray + * @return List of domains + */ + private List parseDomains(JSONArray jsonArray){ + List list_tmp = new ArrayList<>(); + for(int i = 0; i < jsonArray.length(); i++){ + try { + list_tmp.add(jsonArray.getString(i)); + } catch (JSONException ignored) {} + } + return list_tmp; + } + + /** * Parse Tags * @param jsonArray JSONArray diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/client/APIResponse.java b/app/src/main/java/fr/gouv/etalab/mastodon/client/APIResponse.java index 4e19e2355..9ac49ff6f 100644 --- a/app/src/main/java/fr/gouv/etalab/mastodon/client/APIResponse.java +++ b/app/src/main/java/fr/gouv/etalab/mastodon/client/APIResponse.java @@ -31,6 +31,7 @@ public class APIResponse { private List notifications = null; private List relationships = null; private List filters = null; + private List domains = null; private List lists = null; private List emojis = null; private fr.gouv.etalab.mastodon.client.Entities.Error error = null; @@ -132,4 +133,12 @@ public class APIResponse { public void setFilters(List filters) { this.filters = filters; } + + public List getDomains() { + return domains; + } + + public void setDomains(List domains) { + this.domains = domains; + } } diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/drawers/DomainsListAdapter.java b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/DomainsListAdapter.java new file mode 100644 index 000000000..13a4c0aac --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/drawers/DomainsListAdapter.java @@ -0,0 +1,126 @@ +package fr.gouv.etalab.mastodon.drawers; +/* Copyright 2018 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program 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. + * + * Mastalab 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 Mastalab; if not, + * see . */ + +import android.content.Context; +import android.content.DialogInterface; +import android.support.annotation.NonNull; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import java.util.List; + +import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveDomainsInterface; + + +/** + * Created by Thomas on 26/09/2018. + * Adapter for domains + */ +public class DomainsListAdapter extends RecyclerView.Adapter implements OnRetrieveDomainsInterface { + + private List domains; + private LayoutInflater layoutInflater; + private Context context; + private DomainsListAdapter domainsListAdapter; + private RelativeLayout textviewNoAction; + + public DomainsListAdapter(Context context, List domains, RelativeLayout textviewNoAction){ + this.context = context; + layoutInflater = LayoutInflater.from(context); + this.domains = domains; + this.domainsListAdapter = this; + this.textviewNoAction = textviewNoAction; + } + + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new ViewHolder(layoutInflater.inflate(R.layout.drawer_domain, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { + final DomainsListAdapter.ViewHolder holder = (DomainsListAdapter.ViewHolder) viewHolder; + final String domain = domains.get(position); + + holder.domain_name.setText(domain); + holder.domain_delete.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setMessage(context.getString(R.string.unblock_domain_confirm_message, domain)); + builder.setIcon(android.R.drawable.ic_dialog_alert) + .setTitle(R.string.unblock_domain_confirm) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + domains.remove(domain); + domainsListAdapter.notifyItemRemoved(holder.getAdapterPosition()); + if( domains.size() == 0 && textviewNoAction != null && textviewNoAction.getVisibility() == View.GONE) + textviewNoAction.setVisibility(View.VISIBLE); + dialog.dismiss(); + } + }) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + }); + + + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public int getItemCount() { + return domains.size(); + } + + + + @Override + public void onRetrieveDomains(APIResponse apiResponse) { + + } + + private class ViewHolder extends RecyclerView.ViewHolder{ + TextView domain_name; + ImageView domain_delete; + + ViewHolder(View itemView) { + super(itemView); + domain_name = itemView.findViewById(R.id.domain_name); + domain_delete = itemView.findViewById(R.id.domain_delete); + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayMutedInstanceFragment.java b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayMutedInstanceFragment.java new file mode 100644 index 000000000..f0625e250 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/fragments/DisplayMutedInstanceFragment.java @@ -0,0 +1,205 @@ +package fr.gouv.etalab.mastodon.fragments; +/* Copyright 2018 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program 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. + * + * Mastalab 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 Mastalab; if not, + * see . */ + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v4.app.Fragment; +import android.support.v4.content.ContextCompat; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.DividerItemDecoration; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +import fr.gouv.etalab.mastodon.R; +import fr.gouv.etalab.mastodon.asynctasks.RetrieveDomainsAsyncTask; +import fr.gouv.etalab.mastodon.client.APIResponse; +import fr.gouv.etalab.mastodon.drawers.DomainsListAdapter; +import fr.gouv.etalab.mastodon.helper.Helper; +import fr.gouv.etalab.mastodon.interfaces.OnRetrieveDomainsInterface; + + +/** + * Created by Thomas on 26/09/2018. + * Fragment to display muted instances + */ +public class DisplayMutedInstanceFragment extends Fragment implements OnRetrieveDomainsInterface { + + private boolean flag_loading; + private Context context; + private AsyncTask asyncTask; + private DomainsListAdapter domainsListAdapter; + private String max_id; + private List domains; + private RelativeLayout mainLoader, nextElementLoader, textviewNoAction; + private boolean firstLoad; + private SwipeRefreshLayout swipeRefreshLayout; + private boolean swiped; + private RecyclerView lv_domains; + + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + View rootView = inflater.inflate(R.layout.fragment_muted_instances, container, false); + + context = getContext(); + Bundle bundle = this.getArguments(); + domains = new ArrayList<>(); + max_id = null; + firstLoad = true; + flag_loading = true; + swiped = false; + + swipeRefreshLayout = rootView.findViewById(R.id.swipeContainer); + lv_domains = rootView.findViewById(R.id.lv_domains); + lv_domains.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); + mainLoader = rootView.findViewById(R.id.loader); + nextElementLoader = rootView.findViewById(R.id.loading_next_domains); + textviewNoAction = rootView.findViewById(R.id.no_action); + mainLoader.setVisibility(View.VISIBLE); + nextElementLoader.setVisibility(View.GONE); + domainsListAdapter = new DomainsListAdapter(context, this.domains, textviewNoAction); + lv_domains.setAdapter(domainsListAdapter); + + final LinearLayoutManager mLayoutManager; + mLayoutManager = new LinearLayoutManager(context); + lv_domains.setLayoutManager(mLayoutManager); + lv_domains.addOnScrollListener(new RecyclerView.OnScrollListener() { + public void onScrolled(RecyclerView recyclerView, int dx, int dy) + { + if(dy > 0) { + int visibleItemCount = mLayoutManager.getChildCount(); + int totalItemCount = mLayoutManager.getItemCount(); + int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); + if (firstVisibleItem + visibleItemCount == totalItemCount) { + if (!flag_loading) { + flag_loading = true; + asyncTask = new RetrieveDomainsAsyncTask(context, max_id, DisplayMutedInstanceFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); nextElementLoader.setVisibility(View.VISIBLE); + } + } else { + nextElementLoader.setVisibility(View.GONE); + } + } + } + }); + swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + max_id = null; + domains = new ArrayList<>(); + firstLoad = true; + flag_loading = true; + swiped = true; + asyncTask = new RetrieveDomainsAsyncTask(context, max_id, DisplayMutedInstanceFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + }); + SharedPreferences sharedpreferences = context.getSharedPreferences(Helper.APP_PREFS, Context.MODE_PRIVATE); + int theme = sharedpreferences.getInt(Helper.SET_THEME, Helper.THEME_DARK); + switch (theme){ + case Helper.THEME_LIGHT: + swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4, + R.color.mastodonC2, + R.color.mastodonC3); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.white)); + break; + case Helper.THEME_DARK: + swipeRefreshLayout.setColorSchemeResources(R.color.mastodonC4__, + R.color.mastodonC4, + R.color.mastodonC4); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.mastodonC1_)); + break; + case Helper.THEME_BLACK: + swipeRefreshLayout.setColorSchemeResources(R.color.dark_icon, + R.color.mastodonC2, + R.color.mastodonC3); + swipeRefreshLayout.setProgressBackgroundColorSchemeColor(ContextCompat.getColor(context, R.color.black_3)); + break; + } + + asyncTask = new RetrieveDomainsAsyncTask(context, max_id, DisplayMutedInstanceFragment.this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + return rootView; + } + + @Override + public void onCreate(Bundle saveInstance) + { + super.onCreate(saveInstance); + } + + + + @Override + public void onAttach(Context context) { + super.onAttach(context); + this.context = context; + } + + public void onDestroy() { + super.onDestroy(); + if(asyncTask != null && asyncTask.getStatus() == AsyncTask.Status.RUNNING) + asyncTask.cancel(true); + } + + public void scrollToTop(){ + if( lv_domains != null) + lv_domains.setAdapter(domainsListAdapter); + } + + @Override + public void onRetrieveDomains(APIResponse apiResponse) { + mainLoader.setVisibility(View.GONE); + nextElementLoader.setVisibility(View.GONE); + if( apiResponse.getError() != null){ + Toast.makeText(context, apiResponse.getError().getError(),Toast.LENGTH_LONG).show(); + swipeRefreshLayout.setRefreshing(false); + swiped = false; + flag_loading = false; + return; + } + flag_loading = (apiResponse.getMax_id() == null ); + List domains = apiResponse.getDomains(); + if( !swiped && firstLoad && (domains == null || domains.size() == 0)) + textviewNoAction.setVisibility(View.VISIBLE); + else + textviewNoAction.setVisibility(View.GONE); + max_id = apiResponse.getMax_id(); + if( swiped ){ + domainsListAdapter = new DomainsListAdapter(context, this.domains, textviewNoAction); + lv_domains.setAdapter(domainsListAdapter); + swiped = false; + } + if( domains != null && domains.size() > 0) { + this.domains.addAll(domains); + domainsListAdapter.notifyDataSetChanged(); + } + swipeRefreshLayout.setRefreshing(false); + firstLoad = false; + } + + + +} diff --git a/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveDomainsInterface.java b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveDomainsInterface.java new file mode 100644 index 000000000..980a1c772 --- /dev/null +++ b/app/src/main/java/fr/gouv/etalab/mastodon/interfaces/OnRetrieveDomainsInterface.java @@ -0,0 +1,26 @@ +/* Copyright 2017 Thomas Schneider + * + * This file is a part of Mastalab + * + * This program 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. + * + * Mastalab 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 Mastalab; if not, + * see . */ +package fr.gouv.etalab.mastodon.interfaces; + + +import fr.gouv.etalab.mastodon.client.APIResponse; + +/** + * Created by Thomas on 26/09/2018. + * Interface when blocked domains have been retrieved + */ +public interface OnRetrieveDomainsInterface { + void onRetrieveDomains(APIResponse apiResponse); +} diff --git a/app/src/main/res/layout/drawer_domain.xml b/app/src/main/res/layout/drawer_domain.xml new file mode 100644 index 000000000..89cc8bc56 --- /dev/null +++ b/app/src/main/res/layout/drawer_domain.xml @@ -0,0 +1,45 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_muted_instances.xml b/app/src/main/res/layout/fragment_muted_instances.xml new file mode 100644 index 000000000..48033adb2 --- /dev/null +++ b/app/src/main/res/layout/fragment_muted_instances.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index ab9d3dbf2..de00be725 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -67,6 +67,10 @@ android:id="@+id/nav_muted" android:icon="@drawable/ic_volume_mute" android:title="@string/muted_menu" /> + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 478d15af5..e579f72a1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -622,6 +622,10 @@ Enable time slot How To Videos Fetching remote thread! + No blocked domains! + Unblock domain + Are you sure to unblock %s? + Blocked domains Never