summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas <tschneider.ac@gmail.com>2022-12-15 18:26:43 +0100
committerThomas <tschneider.ac@gmail.com>2022-12-15 18:26:43 +0100
commit2a675da7c272ac7dae21561e962fa800d26272dd (patch)
treedf6e0c1988c07f5c80e8fc03b9878cce6da5f053
parent12981deafb1dfb691ba075a330fe1b76f9371524 (diff)
parent4ec3a430bd90cde6be7428ada0fab3020992a334 (diff)
Merge branch 'develop'3.11.2
-rw-r--r--app/build.gradle4
-rw-r--r--app/src/main/assets/release_notes/notes.json5
-rw-r--r--app/src/main/java/app/fedilab/android/BaseMainActivity.java8
-rw-r--r--app/src/main/java/app/fedilab/android/activities/ActionActivity.java6
-rw-r--r--app/src/main/java/app/fedilab/android/activities/MastodonListActivity.java16
-rw-r--r--app/src/main/java/app/fedilab/android/activities/ProfileActivity.java34
-rw-r--r--app/src/main/java/app/fedilab/android/client/entities/api/Account.java12
-rw-r--r--app/src/main/java/app/fedilab/android/client/entities/app/MutedAccounts.java249
-rw-r--r--app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java2
-rw-r--r--app/src/main/java/app/fedilab/android/helper/Helper.java15
-rw-r--r--app/src/main/java/app/fedilab/android/helper/SpannableHelper.java4
-rw-r--r--app/src/main/java/app/fedilab/android/helper/TimelineHelper.java21
-rw-r--r--app/src/main/java/app/fedilab/android/sqlite/Sqlite.java16
-rw-r--r--app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java27
-rw-r--r--app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java10
-rw-r--r--app/src/main/java/app/fedilab/android/ui/fragment/media/FragmentMedia.java2
-rw-r--r--app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonAccount.java8
-rw-r--r--app/src/main/java/app/fedilab/android/viewmodel/mastodon/AccountsVM.java101
-rw-r--r--app/src/main/res/layout/activity_actions.xml24
-rw-r--r--app/src/main/res/layout/activity_list.xml4
-rw-r--r--app/src/main/res/layout/drawer_account.xml12
-rw-r--r--app/src/main/res/menu/activity_profile.xml5
-rw-r--r--app/src/main/res/menu/menu_list.xml5
-rw-r--r--app/src/main/res/menu/option_toot.xml4
-rw-r--r--app/src/main/res/values-cs/strings.xml68
-rw-r--r--app/src/main/res/values-it/strings.xml327
-rw-r--r--app/src/main/res/values-sc/strings.xml6
-rw-r--r--app/src/main/res/values-tr/strings.xml18
-rw-r--r--app/src/main/res/values/strings.xml6
-rw-r--r--src/fdroid/fastlane/metadata/android/en/changelogs/447.txt4
-rw-r--r--src/fdroid/fastlane/metadata/android/en/changelogs/448.txt7
31 files changed, 970 insertions, 60 deletions
diff --git a/app/build.gradle b/app/build.gradle
index d22d76ee0..413135ac4 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -13,8 +13,8 @@ android {
defaultConfig {
minSdk 21
targetSdk 32
- versionCode 446
- versionName "3.11.0"
+ versionCode 448
+ versionName "3.11.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions "default"
diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json
index f3818d4c8..36a49beec 100644
--- a/app/src/main/assets/release_notes/notes.json
+++ b/app/src/main/assets/release_notes/notes.json
@@ -1,5 +1,10 @@
[
{
+ "version": "3.11.2",
+ "code": "448",
+ "note": "Added:\n- Mute/Unmute accounts in the Home timeline from their messages or their profiles\n- Add all users from a list to \"Muted home\" in one click\n- Display/Manage users that are muted for home\n\nFixed:\n- Timeline crashes"
+ },
+ {
"version": "3.11.0",
"code": "446",
"note": "Added:\n- Display all messages in threads from remote instances (when possible)\n- Allow to unmute/unfollow/unpin a tag from tag timelines\n- Display most used accounts in header menu for an easy switch\n- Automatically add the tag when composing from a tag timeline\n- Add a translate button at the bottom of messages (default: disabled)\n- Add account role in profiles\n- Translate morse\n\nChanged:\n- Disable animations after a refresh\n\nFixed:\n- Contact not working when composing\n- Status bar for black theme\n- Message duplicated in conversations when edited\n- Color issue on Android 5\n- Several crashes"
diff --git a/app/src/main/java/app/fedilab/android/BaseMainActivity.java b/app/src/main/java/app/fedilab/android/BaseMainActivity.java
index 7e43d4d0f..09fdb201b 100644
--- a/app/src/main/java/app/fedilab/android/BaseMainActivity.java
+++ b/app/src/main/java/app/fedilab/android/BaseMainActivity.java
@@ -127,6 +127,7 @@ import app.fedilab.android.client.entities.api.Status;
import app.fedilab.android.client.entities.app.Account;
import app.fedilab.android.client.entities.app.BaseAccount;
import app.fedilab.android.client.entities.app.BottomMenu;
+import app.fedilab.android.client.entities.app.MutedAccounts;
import app.fedilab.android.client.entities.app.Pinned;
import app.fedilab.android.client.entities.app.PinnedTimeline;
import app.fedilab.android.client.entities.app.StatusCache;
@@ -164,6 +165,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
public static status networkAvailable = UNKNOWN;
public static Instance instanceInfo;
public static List<Filter> mainFilters;
+ public static List<app.fedilab.android.client.entities.api.Account> filteredAccounts;
public static boolean filterFetched;
public static boolean show_boosts, show_replies, show_art_nsfw;
public static String regex_home, regex_local, regex_public;
@@ -302,7 +304,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
} else {
BaseMainActivity.currentToken = sharedpreferences.getString(Helper.PREF_USER_TOKEN, null);
}
-
+ filteredAccounts = new ArrayList<>();
mamageNewIntent(getIntent());
filterFetched = false;
networkStateReceiver = new NetworkStateReceiver();
@@ -565,6 +567,10 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
currentAccount = new Account(BaseMainActivity.this).getConnectedAccount();
//Delete cache older than 7 days
new StatusCache(BaseMainActivity.this).deleteForAllAccountAfter7Days();
+ MutedAccounts mutedAccounts = new MutedAccounts(BaseMainActivity.this).getMutedAccount(currentAccount);
+ if (mutedAccounts != null && mutedAccounts.accounts != null) {
+ filteredAccounts = mutedAccounts.accounts;
+ }
} catch (DBException e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/app/fedilab/android/activities/ActionActivity.java b/app/src/main/java/app/fedilab/android/activities/ActionActivity.java
index faa7a7ecb..aab8386c0 100644
--- a/app/src/main/java/app/fedilab/android/activities/ActionActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/ActionActivity.java
@@ -54,11 +54,12 @@ public class ActionActivity extends BaseBarActivity {
binding.muted.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.MUTED_TIMELINE));
binding.blocked.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BLOCKED_TIMELINE));
binding.domainBlock.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.BLOCKED_DOMAIN_TIMELINE));
+ binding.mutedHome.setOnClickListener(v -> displayTimeline(Timeline.TimeLineEnum.MUTED_TIMELINE_HOME));
}
private void displayTimeline(Timeline.TimeLineEnum type) {
canGoBack = true;
- if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE) {
+ if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE || type == Timeline.TimeLineEnum.MUTED_TIMELINE_HOME) {
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonAccount = new FragmentMastodonAccount();
@@ -114,6 +115,9 @@ public class ActionActivity extends BaseBarActivity {
case BLOCKED_DOMAIN_TIMELINE:
setTitle(R.string.blocked_domains);
break;
+ case MUTED_TIMELINE_HOME:
+ setTitle(R.string.muted_menu_home);
+ break;
}
}
diff --git a/app/src/main/java/app/fedilab/android/activities/MastodonListActivity.java b/app/src/main/java/app/fedilab/android/activities/MastodonListActivity.java
index 0d4516522..0d6219316 100644
--- a/app/src/main/java/app/fedilab/android/activities/MastodonListActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/MastodonListActivity.java
@@ -143,6 +143,22 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
if (item.getItemId() == android.R.id.home) {
onBackPressed();
return true;
+ } else if (item.getItemId() == R.id.action_user_mute_home) {
+ AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MastodonListActivity.this, Helper.dialogStyle());
+ dialogBuilder.setTitle(R.string.put_all_accounts_in_home_muted);
+ dialogBuilder.setPositiveButton(R.string.mute_them_all, (dialog, id) -> {
+ timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, null, null, 0)
+ .observe(MastodonListActivity.this, accounts -> {
+ if (accounts != null && accounts.size() > 0) {
+ for (Account account : accounts) {
+ accountsVM.muteHome(MainActivity.currentAccount, account);
+ }
+ }
+ });
+ dialog.dismiss();
+ });
+ dialogBuilder.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
+ dialogBuilder.show();
} else if (item.getItemId() == R.id.action_manage_users) {
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MastodonListActivity.this, Helper.dialogStyle());
PopupManageAccountsListBinding popupManageAccountsListBinding = PopupManageAccountsListBinding.inflate(getLayoutInflater());
diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java
index 79ac5c58d..97b13d769 100644
--- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java
+++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java
@@ -117,6 +117,7 @@ public class ProfileActivity extends BaseActivity {
private String mention_str;
private WellKnownNodeinfo.NodeInfo nodeInfo;
private boolean checkRemotely;
+ private boolean homeMuted;
private final BroadcastReceiver broadcast_data = new BroadcastReceiver() {
@Override
@@ -144,6 +145,7 @@ public class ProfileActivity extends BaseActivity {
Bundle b = getIntent().getExtras();
binding.accountFollow.setEnabled(false);
checkRemotely = false;
+ homeMuted = false;
if (b != null) {
account = (Account) b.getSerializable(Helper.ARG_ACCOUNT);
account_id = b.getString(Helper.ARG_USER_ID, null);
@@ -185,6 +187,8 @@ public class ProfileActivity extends BaseActivity {
Toasty.error(ProfileActivity.this, getString(R.string.toast_error), Toast.LENGTH_LONG).show();
finish();
}
+ //Check if account is homeMuted
+ accountsVM.isMuted(currentAccount, account).observe(this, result -> homeMuted = result != null && result);
LocalBroadcastManager.getInstance(ProfileActivity.this).registerReceiver(broadcast_data, new IntentFilter(Helper.BROADCAST_DATA));
}
@@ -685,9 +689,11 @@ public class ProfileActivity extends BaseActivity {
menu.findItem(R.id.action_endorse).setVisible(false);
menu.findItem(R.id.action_direct_message).setVisible(false);
menu.findItem(R.id.action_add_to_list).setVisible(false);
+ menu.findItem(R.id.action_mute_home).setVisible(false);
} else {
menu.findItem(R.id.action_block).setVisible(true);
menu.findItem(R.id.action_mute).setVisible(true);
+ menu.findItem(R.id.action_mute_home).setVisible(true);
menu.findItem(R.id.action_timed_mute).setVisible(true);
menu.findItem(R.id.action_mention).setVisible(true);
}
@@ -696,6 +702,7 @@ public class ProfileActivity extends BaseActivity {
if (!relationship.following) {
menu.findItem(R.id.action_hide_boost).setVisible(false);
menu.findItem(R.id.action_endorse).setVisible(false);
+ menu.findItem(R.id.action_mute_home).setVisible(false);
}
if (relationship.blocking) {
menu.findItem(R.id.action_block).setTitle(R.string.action_unblock);
@@ -713,6 +720,11 @@ public class ProfileActivity extends BaseActivity {
} else {
menu.findItem(R.id.action_hide_boost).setTitle(getString(R.string.show_boost, account.username));
}
+ if (homeMuted) {
+ menu.findItem(R.id.action_mute_home).setTitle(getString(R.string.unmute_home));
+ } else {
+ menu.findItem(R.id.action_mute_home).setTitle(getString(R.string.mute_home));
+ }
}
}
return true;
@@ -989,6 +1001,28 @@ public class ProfileActivity extends BaseActivity {
});
builderInner.show();
}
+ } else if (itemId == R.id.action_mute_home) {
+ AlertDialog.Builder builderInner = new AlertDialog.Builder(ProfileActivity.this, Helper.dialogStyle());
+ builderInner.setMessage(account.acct);
+ builderInner.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
+ if (homeMuted) {
+ builderInner.setTitle(R.string.unmute_home);
+ builderInner.setPositiveButton(R.string.action_unmute, (dialog, which) -> accountsVM.unmuteHome(currentAccount, account)
+ .observe(ProfileActivity.this, account -> {
+ homeMuted = false;
+ invalidateOptionsMenu();
+ Toasty.info(ProfileActivity.this, getString(R.string.toast_unmute), Toasty.LENGTH_LONG).show();
+ }));
+ } else {
+ builderInner.setTitle(R.string.mute_home);
+ builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> accountsVM.muteHome(currentAccount, account)
+ .observe(ProfileActivity.this, account -> {
+ homeMuted = true;
+ invalidateOptionsMenu();
+ Toasty.info(ProfileActivity.this, getString(R.string.toast_mute), Toasty.LENGTH_LONG).show();
+ }));
+ }
+ builderInner.show();
} else if (itemId == R.id.action_timed_mute) {
MastodonHelper.scheduleBoost(ProfileActivity.this, MastodonHelper.ScheduleType.TIMED_MUTED, null, account, rs -> {
this.relationship = rs;
diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java
index ae0b71ae0..9c423554c 100644
--- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java
+++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java
@@ -19,6 +19,8 @@ import android.content.Context;
import android.text.Spannable;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
@@ -148,4 +150,14 @@ public class Account implements Serializable {
public LinkedHashMap<Integer, Field.FieldParams> fields;
}
+
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ boolean same = false;
+ if (obj instanceof Account) {
+ same = this.id.equals(((Account) obj).id);
+ }
+ return same;
+ }
}
diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/MutedAccounts.java b/app/src/main/java/app/fedilab/android/client/entities/app/MutedAccounts.java
new file mode 100644
index 000000000..5932aac33
--- /dev/null
+++ b/app/src/main/java/app/fedilab/android/client/entities/app/MutedAccounts.java
@@ -0,0 +1,249 @@
+package app.fedilab.android.client.entities.app;
+/* Copyright 2022 Thomas Schneider
+ *
+ * This file is a part of Fedilab
+ *
+ * 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.
+ *
+ * Fedilab 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 Fedilab; if not,
+ * see <http://www.gnu.org/licenses>. */
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+
+import com.google.gson.Gson;
+import com.google.gson.annotations.SerializedName;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import app.fedilab.android.client.entities.api.Account;
+import app.fedilab.android.exception.DBException;
+import app.fedilab.android.sqlite.Sqlite;
+
+
+public class MutedAccounts implements Serializable {
+
+
+ private transient final SQLiteDatabase db;
+ @SerializedName("id")
+ public long id = -1;
+ @SerializedName("instance")
+ public String instance;
+ @SerializedName("user_id")
+ public String user_id;
+ @SerializedName("type")
+ public Timeline.TimeLineEnum type;
+ @SerializedName("accounts")
+ public List<Account> accounts;
+
+ public MutedAccounts() {
+ db = null;
+ }
+
+ public MutedAccounts(Context context) {
+ //Creation of the DB with tables
+ this.db = Sqlite.getInstance(context.getApplicationContext(), Sqlite.DB_NAME, null, Sqlite.DB_VERSION).open();
+ }
+
+
+ /**
+ * Serialized a list of BaseAccount class
+ *
+ * @param accounts List of {@link Account} to serialize
+ * @return String serialized emoji list
+ */
+ public static String accountListToStringStorage(List<Account> accounts) {
+ Gson gson = new Gson();
+ try {
+ return gson.toJson(accounts);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ /**
+ * Unserialized a BaseAccount List
+ *
+ * @param serializedAccounts String serialized BaseAccount list
+ * @return List of {@link Account}
+ */
+ public static List<Account> restoreAccountsFromString(String serializedAccounts) {
+ Gson gson = new Gson();
+ try {
+ return gson.fromJson(serializedAccounts, new TypeToken<List<Account>>() {
+ }.getType());
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public void delete() {
+ db.delete(Sqlite.TABLE_MUTED, null, null);
+ }
+
+ /**
+ * Insert an Account in muted account in db
+ *
+ * @param forAccount {@link BaseAccount}
+ * @param target {@link Account}
+ * @return long - db id
+ * @throws DBException exception with database
+ */
+ public long muteAccount(BaseAccount forAccount, Account target) throws DBException {
+ if (db == null) {
+ throw new DBException("db is null. Wrong initialization.");
+ }
+ boolean insert = false;
+ MutedAccounts mutedAccounts = getMutedAccount(forAccount);
+ ContentValues values = new ContentValues();
+ if (mutedAccounts == null) {
+ mutedAccounts = new MutedAccounts();
+ mutedAccounts.accounts = new ArrayList<>();
+ mutedAccounts.type = Timeline.TimeLineEnum.HOME;
+ values.put(Sqlite.COL_INSTANCE, forAccount.instance);
+ values.put(Sqlite.COL_USER_ID, forAccount.user_id);
+ insert = true;
+ values.put(Sqlite.COL_TYPE, mutedAccounts.type.getValue());
+ } else if (mutedAccounts.accounts == null) {
+ mutedAccounts.accounts = new ArrayList<>();
+ }
+ if (!mutedAccounts.accounts.contains(target)) {
+ mutedAccounts.accounts.add(target);
+ }
+ values.put(Sqlite.COL_MUTED_ACCOUNTS, accountListToStringStorage(mutedAccounts.accounts));
+
+ //Inserts or updates
+ try {
+ if (insert) {
+ return db.insertOrThrow(Sqlite.TABLE_MUTED, null, values);
+ } else {
+ return db.update(Sqlite.TABLE_MUTED,
+ values, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " = ?",
+ new String[]{forAccount.user_id, forAccount.instance});
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+
+ /**
+ * Remove an Account in muted account in db
+ *
+ * @param forAccount {@link BaseAccount}
+ * @param target {@link Account}
+ * @return long - db id
+ * @throws DBException exception with database
+ */
+ public long unMuteAccount(BaseAccount forAccount, Account target) throws DBException {
+ if (db == null) {
+ throw new DBException("db is null. Wrong initialization.");
+ }
+ boolean insert = false;
+ MutedAccounts mutedAccounts = getMutedAccount(forAccount);
+ ContentValues values = new ContentValues();
+ if (mutedAccounts == null) {
+ mutedAccounts = new MutedAccounts();
+ mutedAccounts.accounts = new ArrayList<>();
+ mutedAccounts.type = Timeline.TimeLineEnum.HOME;
+ values.put(Sqlite.COL_INSTANCE, forAccount.instance);
+ values.put(Sqlite.COL_USER_ID, forAccount.user_id);
+ insert = true;
+ values.put(Sqlite.COL_TYPE, mutedAccounts.type.getValue());
+ } else if (mutedAccounts.accounts == null) {
+ mutedAccounts.accounts = new ArrayList<>();
+ }
+ mutedAccounts.accounts.remove(target);
+ values.put(Sqlite.COL_MUTED_ACCOUNTS, accountListToStringStorage(mutedAccounts.accounts));
+
+ //Inserts or updates
+ try {
+ if (insert) {
+ return db.insertOrThrow(Sqlite.TABLE_MUTED, null, values);
+ } else {
+ return db.update(Sqlite.TABLE_MUTED,
+ values, Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " = ?",
+ new String[]{forAccount.user_id, forAccount.instance});
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ /**
+ * Check if an account is muted in db
+ *
+ * @param forAccount {@link BaseAccount}
+ * @param target {@link Account}
+ * @return MutedAccounts - {@link MutedAccounts}
+ */
+ public boolean isMuted(BaseAccount forAccount, Account target) throws DBException {
+ if (db == null) {
+ throw new DBException("db is null. Wrong initialization.");
+ }
+ MutedAccounts mutedAccounts = getMutedAccount(forAccount);
+ if (mutedAccounts != null && mutedAccounts.accounts != null) {
+ for (Account account : mutedAccounts.accounts) {
+ if (account.id.equals(target.id)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the MutedAccounts for an account
+ *
+ * @param account Account
+ * @return MutedAccounts - {@link MutedAccounts}
+ */
+ public MutedAccounts getMutedAccount(BaseAccount account) throws DBException {
+ if (db == null) {
+ throw new DBException("db is null. Wrong initialization.");
+ }
+ try {
+ Cursor c = db.query(Sqlite.TABLE_MUTED, null, Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND " + Sqlite.COL_USER_ID + " = '" + account.user_id + "'", null, null, null, null, "1");
+ return convertCursorToMuted(c);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Read cursor and hydrate without closing it
+ *
+ * @param c - Cursor
+ * @return MutedAccounts
+ */
+ private MutedAccounts convertCursorToMuted(Cursor c) {
+ if (c.getCount() == 0) {
+ c.close();
+ return null;
+ }
+ //Take the first element
+ c.moveToFirst();
+ MutedAccounts mutedAccounts = new MutedAccounts();
+ mutedAccounts.id = c.getInt(c.getColumnIndexOrThrow(Sqlite.COL_ID));
+ mutedAccounts.instance = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_INSTANCE));
+ mutedAccounts.user_id = c.getString(c.getColumnIndexOrThrow(Sqlite.COL_USER_ID));
+ mutedAccounts.accounts = restoreAccountsFromString(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_MUTED_ACCOUNTS)));
+ mutedAccounts.type = Timeline.TimeLineEnum.valueOf(c.getString(c.getColumnIndexOrThrow(Sqlite.COL_TYPE)));
+ c.close();
+ return mutedAccounts;
+ }
+}
diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java
index 0f5f6046b..109a8790f 100644
--- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java
+++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java
@@ -388,6 +388,8 @@ public class Timeline {
ACCOUNT_TIMELINE("ACCOUNT_TIMELINE"),
@SerializedName("MUTED_TIMELINE")
MUTED_TIMELINE("MUTED_TIMELINE"),
+ @SerializedName("MUTED_TIMELINE_HOME")
+ MUTED_TIMELINE_HOME("MUTED_TIMELINE_HOME"),
@SerializedName("BOOKMARK_TIMELINE")
BOOKMARK_TIMELINE("BOOKMARK_TIMELINE"),
@SerializedName("BLOCKED_DOMAIN_TIMELINE")
diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java
index 2b1aa30ab..e1d55937b 100644
--- a/app/src/main/java/app/fedilab/android/helper/Helper.java
+++ b/app/src/main/java/app/fedilab/android/helper/Helper.java
@@ -1953,4 +1953,19 @@ public class Helper {
public interface OnAttachmentCopied {
void onAttachmentCopied(Attachment attachment);
}
+
+ public static void addMutedAccount(app.fedilab.android.client.entities.api.Account target) {
+ if (MainActivity.filteredAccounts == null) {
+ MainActivity.filteredAccounts = new ArrayList<>();
+ }
+ if (!MainActivity.filteredAccounts.contains(target)) {
+ MainActivity.filteredAccounts.add(target);
+ }
+ }
+
+ public static void removeMutedAccount(app.fedilab.android.client.entities.api.Account target) {
+ if (MainActivity.filteredAccounts != null) {
+ MainActivity.filteredAccounts.remove(target);
+ }
+ }
}
diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java
index 0d5b7bf38..03e9a52c5 100644
--- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java
+++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java
@@ -494,7 +494,9 @@ public class SpannableHelper {
contentUrl = new SpannableString(Html.fromHtml(value, Html.FROM_HTML_MODE_LEGACY));
else
contentUrl = new SpannableString(Html.fromHtml(value));
-
+ if (contentUrl.toString().trim().isEmpty()) {
+ continue;
+ }
Pattern word = Pattern.compile(Pattern.quote(contentUrl.toString()));
Matcher matcherLink = word.matcher(content);
while (matcherLink.find()) {
diff --git a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java
index 2f0366d76..66b01ba87 100644
--- a/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java
+++ b/app/src/main/java/app/fedilab/android/helper/TimelineHelper.java
@@ -14,6 +14,8 @@ package app.fedilab.android.helper;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
+import static app.fedilab.android.BaseMainActivity.filteredAccounts;
+
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -35,6 +37,7 @@ import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.client.endpoints.MastodonFiltersService;
+import app.fedilab.android.client.entities.api.Account;
import app.fedilab.android.client.entities.api.Filter;
import app.fedilab.android.client.entities.api.Notification;
import app.fedilab.android.client.entities.api.Status;
@@ -90,6 +93,7 @@ public class TimelineHelper {
}
}
}
+
//If there are filters:
if (BaseMainActivity.mainFilters != null && BaseMainActivity.mainFilters.size() > 0 && statuses != null && statuses.size() > 0) {
@@ -143,6 +147,23 @@ public class TimelineHelper {
Matcher ms = p.matcher(spoilerText);
if (ms.find()) {
status.filteredByApp = filter;
+ continue;
+ }
+ }
+
+ if (filterTimeLineType == Timeline.TimeLineEnum.HOME) {
+ if (filteredAccounts != null && filteredAccounts.size() > 0) {
+