View blocked instances

This commit adds the instances page to the blocks activity to display the instances blocked by the user.
This commit is contained in:
Balazs Toldi 2024-06-30 10:53:45 +02:00
parent b68bf50359
commit 1276435494
13 changed files with 758 additions and 9 deletions

View File

@ -74,6 +74,7 @@ import eu.toldi.infinityforlemmy.bottomsheetfragments.AccountChooserBottomSheetF
import eu.toldi.infinityforlemmy.bottomsheetfragments.CommentMoreBottomSheetFragment;
import eu.toldi.infinityforlemmy.bottomsheetfragments.FlairBottomSheetFragment;
import eu.toldi.infinityforlemmy.fragments.BlockedCommunitiesListingFragment;
import eu.toldi.infinityforlemmy.fragments.BlockedInstancesListingFragment;
import eu.toldi.infinityforlemmy.fragments.BlockedUsersListingFragment;
import eu.toldi.infinityforlemmy.fragments.CommentsListingFragment;
import eu.toldi.infinityforlemmy.fragments.FollowedUsersListingFragment;
@ -318,6 +319,8 @@ public interface AppComponent {
void inject(BlockedUsersListingFragment blockedUsersListingFragment);
void inject(BlockedInstancesListingFragment blockedInstancesListingFragment);
void inject(CommentMoreBottomSheetFragment commentMoreBottomSheetFragment);
void inject(PrivateMessageFragment privateMessageFragment);

View File

@ -15,6 +15,8 @@ import eu.toldi.infinityforlemmy.account.Account;
import eu.toldi.infinityforlemmy.account.AccountDao;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityDao;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityData;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceDao;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserDao;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserData;
import eu.toldi.infinityforlemmy.commentfilter.CommentFilter;
@ -47,7 +49,7 @@ import eu.toldi.infinityforlemmy.user.UserData;
@Database(entities = {Account.class, SubredditData.class, SubscribedSubredditData.class, UserData.class,
SubscribedUserData.class, MultiReddit.class, CustomTheme.class, RecentSearchQuery.class,
ReadPost.class, PostFilter.class, PostFilterUsage.class, AnonymousMultiredditSubreddit.class,
BlockedUserData.class, BlockedCommunityData.class, CommentFilter.class, CommentFilterUsage.class}, version = 28)
BlockedUserData.class, BlockedCommunityData.class, BlockedInstanceData.class, CommentFilter.class, CommentFilterUsage.class}, version = 30)
public abstract class RedditDataRoomDatabase extends RoomDatabase {
public static RedditDataRoomDatabase create(final Context context) {
@ -58,7 +60,9 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase {
MIGRATION_9_10, MIGRATION_10_11, MIGRATION_11_12, MIGRATION_12_13,
MIGRATION_13_14, MIGRATION_14_15, MIGRATION_15_16, MIGRATION_16_17,
MIGRATION_17_18, MIGRATION_18_19, MIGRATION_19_20, MIGRATION_20_21,
MIGRATION_21_22, MIGRATION_22_23, MIGRATION_23_24, MIGRATION_24_25, MIGRATION_25_26, MIGRATION_26_27, MIGRATION_27_28)
MIGRATION_21_22, MIGRATION_22_23, MIGRATION_23_24, MIGRATION_24_25,
MIGRATION_25_26, MIGRATION_26_27, MIGRATION_27_28, MIGRATION_28_29,
MIGRATION_29_30)
.build();
}
@ -72,6 +76,8 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase {
public abstract BlockedCommunityDao blockedCommunityDao();
public abstract BlockedInstanceDao blockedInstanceDao();
public abstract UserDao userDao();
public abstract SubscribedUserDao subscribedUserDao();
@ -445,4 +451,23 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase {
"name_of_usage TEXT NOT NULL, PRIMARY KEY(name, usage, name_of_usage), FOREIGN KEY(name) REFERENCES comment_filter(name) ON DELETE CASCADE)");
}
};
private static final Migration MIGRATION_28_29 = new Migration(28, 29) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE blocked_instances" +
"(domain TEXT, id INTEGER NOT NULL, account_name TEXT NOT NULL, PRIMARY KEY( id, account_name))");
}
};
private static final Migration MIGRATION_29_30 = new Migration(29, 30) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
// Alter table "blocked_instances" to add new columns "instance_name" and "icon"
database.execSQL("ALTER TABLE blocked_instances ADD COLUMN instance_name TEXT");
database.execSQL("ALTER TABLE blocked_instances ADD COLUMN icon TEXT");
}
};
}

View File

@ -9,6 +9,7 @@ import java.util.List;
import eu.toldi.infinityforlemmy.apis.LemmyAPI;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityData;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserData;
import eu.toldi.infinityforlemmy.subreddit.ParseSubredditData;
import eu.toldi.infinityforlemmy.subreddit.SubredditData;
@ -31,10 +32,13 @@ public class FetchBlockedThings {
if (siteInfo != null) {
List<BlockedUserData> blockedUsers = new ArrayList<>();
List<BlockedCommunityData> blockedCommunities = new ArrayList<>();
List<BlockedInstanceData> blockedInstances = new ArrayList<>();
try {
JSONObject siteInfoJson = new JSONObject(siteInfo).getJSONObject("my_user");
JSONArray blockedUsersJson = (siteInfoJson.has("person_blocks")) ? siteInfoJson.getJSONArray("person_blocks") : null;
JSONArray blockedCommunitiesJson = (siteInfoJson.has("community_blocks")) ? siteInfoJson.getJSONArray("community_blocks") : null;
JSONArray blockedInstancesJson = (siteInfoJson.has("instance_blocks")) ? siteInfoJson.getJSONArray("instance_blocks") : null;
if (blockedUsersJson != null) {
for (int i = 0; i < blockedUsersJson.length(); i++) {
JSONObject blockedUserJson = blockedUsersJson.getJSONObject(i).getJSONObject("target");
@ -57,7 +61,29 @@ public class FetchBlockedThings {
blockedCommunities.add(new BlockedCommunityData(blockedCommunityData, accountName));
}
}
fetchBlockedThingsListener.onFetchBlockedThingsSuccess(blockedUsers, blockedCommunities);
if (blockedInstancesJson != null) {
for (int i = 0; i < blockedInstancesJson.length(); i++) {
JSONObject blockedInstanceJson = blockedInstancesJson.getJSONObject(i);
// Get the "instance" object if it exists
JSONObject instanceJson = blockedInstanceJson.has("instance") ? blockedInstanceJson.getJSONObject("instance") : null;
if (instanceJson == null) {
continue;
}
int id = instanceJson.getInt("id");
String domain = instanceJson.getString("domain");
JSONObject siteJson = blockedInstanceJson.has("site") ? blockedInstanceJson.getJSONObject("site") : null;
if (siteJson == null) {
blockedInstances.add(new BlockedInstanceData(id, domain, null, null, accountName));
continue;
}
String name = siteJson.getString("name");
String icon = siteJson.optString("icon");
blockedInstances.add(new BlockedInstanceData(id, domain, name, icon, accountName));
}
}
fetchBlockedThingsListener.onFetchBlockedThingsSuccess(blockedUsers, blockedCommunities, blockedInstances);
} catch (JSONException e) {
e.printStackTrace();
fetchBlockedThingsListener.onFetchBlockedThingsFailure();
@ -78,7 +104,7 @@ public class FetchBlockedThings {
}
public interface FetchBlockedThingsListener {
void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities);
void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities, List<BlockedInstanceData> blockedInstances);
void onFetchBlockedThingsFailure();
}

View File

@ -51,6 +51,7 @@ import eu.toldi.infinityforlemmy.RetrofitHolder;
import eu.toldi.infinityforlemmy.account.FetchBlockedThings;
import eu.toldi.infinityforlemmy.asynctasks.InsertBlockedThings;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityData;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserData;
import eu.toldi.infinityforlemmy.customtheme.CustomThemeWrapper;
import eu.toldi.infinityforlemmy.customviews.ViewPagerBugFixed;
@ -58,6 +59,7 @@ import eu.toldi.infinityforlemmy.customviews.slidr.Slidr;
import eu.toldi.infinityforlemmy.events.GoBackToMainPageEvent;
import eu.toldi.infinityforlemmy.events.SwitchAccountEvent;
import eu.toldi.infinityforlemmy.fragments.BlockedCommunitiesListingFragment;
import eu.toldi.infinityforlemmy.fragments.BlockedInstancesListingFragment;
import eu.toldi.infinityforlemmy.fragments.BlockedUsersListingFragment;
import eu.toldi.infinityforlemmy.utils.SharedPreferencesUtils;
import eu.toldi.infinityforlemmy.utils.Utils;
@ -316,9 +318,9 @@ public class BlockedThingListingActivity extends BaseActivity implements Activit
if (mAccessToken != null && !(!forceLoad && mInsertSuccess)) {
FetchBlockedThings.fetchBlockedThings(mRetrofit.getRetrofit(), mAccessToken, mAccountQualifiedName, new FetchBlockedThings.FetchBlockedThingsListener() {
@Override
public void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities) {
public void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities, List<BlockedInstanceData> blockedInstances) {
InsertBlockedThings.insertBlockedThings(mExecutor, new Handler(), mRedditDataRoomDatabase, mAccountQualifiedName,
blockedCommunities, blockedUsers, () -> {
blockedCommunities, blockedUsers, blockedInstances, () -> {
mInsertSuccess = true;
sectionsPagerAdapter.stopRefreshProgressbar();
});
@ -396,12 +398,20 @@ public class BlockedThingListingActivity extends BaseActivity implements Activit
fragment.setArguments(bundle);
return fragment;
}
case 2: {
BlockedInstancesListingFragment fragment = new BlockedInstancesListingFragment();
Bundle bundle = new Bundle();
bundle.putString(BlockedInstancesListingFragment.EXTRA_ACCOUNT_NAME, mAccountQualifiedName);
bundle.putString(BlockedInstancesListingFragment.EXTRA_ACCESS_TOKEN, mAccessToken);
fragment.setArguments(bundle);
return fragment;
}
}
}
@Override
public int getCount() {
return 2;
return 3;
}
@Override
@ -412,7 +422,7 @@ public class BlockedThingListingActivity extends BaseActivity implements Activit
case 1:
return Utils.getTabTextWithCustomFont(typeface, getString(R.string.users));
case 2:
return Utils.getTabTextWithCustomFont(typeface, getString(R.string.multi_reddits));
return Utils.getTabTextWithCustomFont(typeface, getString(R.string.instances));
}
return null;

View File

@ -83,6 +83,7 @@ import eu.toldi.infinityforlemmy.asynctasks.AddSubredditOrUserToMultiReddit;
import eu.toldi.infinityforlemmy.asynctasks.CheckIsFollowingUser;
import eu.toldi.infinityforlemmy.asynctasks.SwitchAccount;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityData;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserData;
import eu.toldi.infinityforlemmy.bottomsheetfragments.CopyTextBottomSheetFragment;
import eu.toldi.infinityforlemmy.bottomsheetfragments.FABMoreOptionsBottomSheetFragment;
@ -1179,7 +1180,7 @@ public class ViewUserDetailActivity extends BaseActivity implements SortTypeSele
FetchBlockedThings.fetchBlockedThings(mRetrofit.getRetrofit(), mAccessToken, mAccountQualifiedName, new FetchBlockedThings.FetchBlockedThingsListener() {
@Override
public void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities) {
public void onFetchBlockedThingsSuccess(List<BlockedUserData> blockedUsers, List<BlockedCommunityData> blockedCommunities, List<BlockedInstanceData> blockedInstances) {
for (BlockedUserData blockedUserData : blockedUsers) {
if (blockedUserData.getQualifiedName().equals(qualifiedName)) {
isBlocked = true;

View File

@ -0,0 +1,269 @@
package eu.toldi.infinityforlemmy.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import com.bumptech.glide.request.RequestOptions;
import java.util.List;
import java.util.concurrent.Executor;
import butterknife.BindView;
import butterknife.ButterKnife;
import eu.toldi.infinityforlemmy.R;
import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
import eu.toldi.infinityforlemmy.activities.BaseActivity;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.customtheme.CustomThemeWrapper;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import me.zhanghai.android.fastscroll.PopupTextProvider;
import pl.droidsonroids.gif.GifImageView;
import retrofit2.Retrofit;
public class BlockedInstancesRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements PopupTextProvider {
private static final int VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER = 0;
private static final int VIEW_TYPE_FAVORITE_SUBREDDIT = 1;
private static final int VIEW_TYPE_SUBREDDIT_DIVIDER = 2;
private static final int VIEW_TYPE_SUBREDDIT = 3;
private BaseActivity mActivity;
private Executor mExecutor;
private Retrofit mOauthRetrofit;
private RedditDataRoomDatabase mRedditDataRoomDatabase;
private List<BlockedInstanceData> mBlockedInstanceData;
private List<BlockedInstanceData> mFavoriteBlockedInstanceData;
private RequestManager glide;
private ItemClickListener itemClickListener;
private String accessToken;
private String instancename;
private String instanceIconUrl;
private boolean hasClearSelectionRow;
private int primaryTextColor;
private int secondaryTextColor;
public BlockedInstancesRecyclerViewAdapter(BaseActivity activity, Executor executor, Retrofit oauthRetrofit,
RedditDataRoomDatabase redditDataRoomDatabase,
CustomThemeWrapper customThemeWrapper,
String accessToken) {
mActivity = activity;
mExecutor = executor;
glide = Glide.with(activity);
mOauthRetrofit = oauthRetrofit;
mRedditDataRoomDatabase = redditDataRoomDatabase;
this.accessToken = accessToken;
primaryTextColor = customThemeWrapper.getPrimaryTextColor();
secondaryTextColor = customThemeWrapper.getSecondaryTextColor();
}
public BlockedInstancesRecyclerViewAdapter(BaseActivity activity, Executor executor, Retrofit oauthRetrofit,
RedditDataRoomDatabase redditDataRoomDatabase,
CustomThemeWrapper customThemeWrapper,
String accessToken, boolean hasClearSelectionRow,
ItemClickListener itemClickListener) {
this(activity, executor, oauthRetrofit, redditDataRoomDatabase, customThemeWrapper, accessToken);
this.hasClearSelectionRow = hasClearSelectionRow;
this.itemClickListener = itemClickListener;
}
@Override
public int getItemViewType(int position) {
if (mFavoriteBlockedInstanceData != null && mFavoriteBlockedInstanceData.size() > 0) {
if (itemClickListener != null && !hasClearSelectionRow) {
if (position == 0) {
return VIEW_TYPE_SUBREDDIT;
} else if (position == 1) {
return VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER;
} else if (position == mFavoriteBlockedInstanceData.size() + 2) {
return VIEW_TYPE_SUBREDDIT_DIVIDER;
} else if (position <= mFavoriteBlockedInstanceData.size() + 1) {
return VIEW_TYPE_FAVORITE_SUBREDDIT;
} else {
return VIEW_TYPE_SUBREDDIT;
}
} else if (hasClearSelectionRow) {
if (position == 0) {
return VIEW_TYPE_SUBREDDIT;
} else if (position == 1) {
return VIEW_TYPE_SUBREDDIT;
} else if (position == 2) {
return VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER;
} else if (position == mFavoriteBlockedInstanceData.size() + 3) {
return VIEW_TYPE_SUBREDDIT_DIVIDER;
} else if (position <= mFavoriteBlockedInstanceData.size() + 2) {
return VIEW_TYPE_FAVORITE_SUBREDDIT;
} else {
return VIEW_TYPE_SUBREDDIT;
}
} else {
if (position == 0) {
return VIEW_TYPE_FAVORITE_SUBREDDIT_DIVIDER;
} else if (position == mFavoriteBlockedInstanceData.size() + 1) {
return VIEW_TYPE_SUBREDDIT_DIVIDER;
} else if (position <= mFavoriteBlockedInstanceData.size()) {
return VIEW_TYPE_FAVORITE_SUBREDDIT;
} else {
return VIEW_TYPE_SUBREDDIT;
}
}
} else {
return VIEW_TYPE_SUBREDDIT;
}
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new InstanceViewHolder(LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_subscribed_thing, viewGroup, false));
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) {
String name;
String iconUrl;
if (hasClearSelectionRow && viewHolder.getBindingAdapterPosition() == 0) {
((InstanceViewHolder) viewHolder).subredditNameTextView.setText(R.string.all_communities);
viewHolder.itemView.setOnClickListener(view -> itemClickListener.onClick(null));
return;
} else {
int offset = hasClearSelectionRow ? 1 : 0;
BlockedInstanceData instanceData = mBlockedInstanceData.get(viewHolder.getBindingAdapterPosition() - offset);
String domain = mBlockedInstanceData.get(viewHolder.getBindingAdapterPosition() - offset).getDomain();
String instanceName = mBlockedInstanceData.get(viewHolder.getBindingAdapterPosition() - offset).getName();
name = instanceName != null ? instanceName + " (" + domain + ")" : domain;
iconUrl = mBlockedInstanceData.get(viewHolder.getBindingAdapterPosition() - offset).getIcon();
}
if (itemClickListener == null) {
// TODO: 2020-07-29 Add instance view page
}
if (iconUrl == null || iconUrl.equals("")) {
((InstanceViewHolder) viewHolder).iconGifImageView.setVisibility(View.GONE);
} else {
((InstanceViewHolder) viewHolder).iconGifImageView.setVisibility(View.VISIBLE);
glide.load(iconUrl)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(glide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(((InstanceViewHolder) viewHolder).iconGifImageView);
}
((InstanceViewHolder) viewHolder).subredditNameTextView.setText(name);
}
@Override
public int getItemCount() {
if (mBlockedInstanceData != null) {
if (itemClickListener != null) {
return mBlockedInstanceData.size() > 0 ? mBlockedInstanceData.size() + ((hasClearSelectionRow) ? 1 : 0) : 0;
}
return mBlockedInstanceData.size();
}
return 0;
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
glide.clear(((InstanceViewHolder) holder).iconGifImageView);
}
public void blockedInstances(List<BlockedInstanceData> subscribedSubreddits) {
mBlockedInstanceData = subscribedSubreddits;
notifyDataSetChanged();
}
public void setFavoriteSubscribedSubreddits(List<BlockedInstanceData> favoriteBlockedInstanceData) {
mFavoriteBlockedInstanceData = favoriteBlockedInstanceData;
notifyDataSetChanged();
}
public void addInstance(String instancename, String instanceIconUrl) {
this.instancename = instancename;
this.instanceIconUrl = instanceIconUrl;
}
@NonNull
@Override
public String getPopupText(int position) {
switch (getItemViewType(position)) {
case VIEW_TYPE_SUBREDDIT:
if (hasClearSelectionRow && position == 0) {
return "";
} else if (itemClickListener != null && !hasClearSelectionRow && position == 0) {
return "";
} else if (hasClearSelectionRow && position == 1) {
return "";
} else {
int offset;
if (itemClickListener != null) {
if (hasClearSelectionRow) {
offset = (mFavoriteBlockedInstanceData != null && mFavoriteBlockedInstanceData.size() > 0) ?
mFavoriteBlockedInstanceData.size() + 4 : 0;
} else {
offset = (mFavoriteBlockedInstanceData != null && mFavoriteBlockedInstanceData.size() > 0) ?
mFavoriteBlockedInstanceData.size() + 3 : 0;
}
} else {
offset = (mFavoriteBlockedInstanceData != null && mFavoriteBlockedInstanceData.size() > 0) ?
mFavoriteBlockedInstanceData.size() + 2 : 0;
}
return mBlockedInstanceData.get(position - offset).getDomain().substring(0, 1).toUpperCase();
}
case VIEW_TYPE_FAVORITE_SUBREDDIT:
int offset;
if (itemClickListener != null) {
if (hasClearSelectionRow) {
offset = 3;
} else {
offset = 2;
}
} else {
offset = 1;
}
return mFavoriteBlockedInstanceData.get(position - offset).getDomain().substring(0, 1).toUpperCase();
default:
return "";
}
}
public interface ItemClickListener {
void onClick(BlockedInstanceData subredditData);
}
class InstanceViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.thing_icon_gif_image_view_item_subscribed_thing)
GifImageView iconGifImageView;
@BindView(R.id.thing_name_text_view_item_subscribed_thing)
TextView subredditNameTextView;
@BindView(R.id.thing_instance_text_view_item_subscribed_thing)
TextView instanceInstanceTextView;
InstanceViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
if (mActivity.typeface != null) {
subredditNameTextView.setTypeface(mActivity.typeface);
}
subredditNameTextView.setTextColor(primaryTextColor);
}
}
}

View File

@ -12,6 +12,7 @@ import java.util.concurrent.Executor;
import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityDao;
import eu.toldi.infinityforlemmy.blockedcommunity.BlockedCommunityData;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceData;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserDao;
import eu.toldi.infinityforlemmy.blockeduser.BlockedUserData;
@ -22,6 +23,7 @@ public class InsertBlockedThings {
RedditDataRoomDatabase redditDataRoomDatabase, @Nullable String accountName,
List<BlockedCommunityData> blockedCommunityDataList,
List<BlockedUserData> blockedUserDataDataList,
List<BlockedInstanceData> blockedInstanceDataList,
InsertBlockedThingListener insertSubscribedThingListener) {
executor.execute(() -> {
@ -68,6 +70,23 @@ public class InsertBlockedThings {
}
}
if (blockedInstanceDataList != null) {
List<BlockedInstanceData> existingBlockedInstanceDataList =
redditDataRoomDatabase.blockedInstanceDao().getAllInstanceInstancesList(accountName);
Collections.sort(blockedInstanceDataList, (subscribedInstanceData, t1) -> subscribedInstanceData.getDomain().compareToIgnoreCase(t1.getDomain()));
List<String> unblockedInstances = new ArrayList<>();
compareTwoBlockedInstanceList(blockedInstanceDataList, existingBlockedInstanceDataList,
unblockedInstances);
for (String unblocked : unblockedInstances) {
redditDataRoomDatabase.blockedInstanceDao().deleteInstanceUser(unblocked, accountName);
}
for (BlockedInstanceData s : blockedInstanceDataList) {
redditDataRoomDatabase.blockedInstanceDao().insert(s);
}
}
handler.post(insertSubscribedThingListener::insertSuccess);
});
}
@ -124,6 +143,32 @@ public class InsertBlockedThings {
}
}
private static void compareTwoBlockedInstanceList(List<BlockedInstanceData> newBlockedInstances,
List<BlockedInstanceData> oldBlockedInstances,
List<String> unblockedInstances) {
int newIndex = 0;
for (int oldIndex = 0; oldIndex < oldBlockedInstances.size(); oldIndex++) {
if (newIndex >= newBlockedInstances.size()) {
for (; oldIndex < oldBlockedInstances.size(); oldIndex++) {
unblockedInstances.add(oldBlockedInstances.get(oldIndex).getDomain());
}
return;
}
BlockedInstanceData old = oldBlockedInstances.get(oldIndex);
for (; newIndex < newBlockedInstances.size(); newIndex++) {
if (newBlockedInstances.get(newIndex).getDomain().compareToIgnoreCase(old.getDomain()) == 0) {
newIndex++;
break;
}
if (newBlockedInstances.get(newIndex).getDomain().compareToIgnoreCase(old.getDomain()) > 0) {
unblockedInstances.add(old.getDomain());
break;
}
}
}
}
public interface InsertBlockedThingListener {
void insertSuccess();
}

View File

@ -0,0 +1,30 @@
package eu.toldi.infinityforlemmy.blockedinstances;
import androidx.lifecycle.LiveData;
import androidx.room.Dao;
import androidx.room.Insert;
import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import java.util.List;
@Dao
public interface BlockedInstanceDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(BlockedInstanceData instanceData);
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insertAll(List<BlockedInstanceData> blockedUserDataDataList);
@Query("SELECT * FROM blocked_instances WHERE account_name = :accountName AND domain LIKE '%' || :searchQuery || '%' COLLATE NOCASE ORDER BY domain COLLATE NOCASE ASC")
LiveData<List<BlockedInstanceData>> getAllBlockedInstancesWithSearchQuery(String accountName, String searchQuery);
@Query("SELECT * FROM blocked_instances WHERE account_name = :accountName COLLATE NOCASE ORDER BY domain COLLATE NOCASE ASC")
List<BlockedInstanceData> getAllInstanceInstancesList(String accountName);
@Query("SELECT * FROM blocked_instances WHERE domain = :domain COLLATE NOCASE AND account_name = :accountName COLLATE NOCASE LIMIT 1")
BlockedInstanceData getInstanceUser(String domain, String accountName);
@Query("DELETE FROM blocked_instances WHERE domain = :domain COLLATE NOCASE AND account_name = :accountName COLLATE NOCASE")
void deleteInstanceUser(String domain, String accountName);
}

View File

@ -0,0 +1,57 @@
package eu.toldi.infinityforlemmy.blockedinstances;
import androidx.annotation.NonNull;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
@Entity(tableName = "blocked_instances", primaryKeys = {"id", "account_name"})
public class BlockedInstanceData {
@ColumnInfo(name = "id")
private final int id;
@ColumnInfo(name = "domain")
private String domain;
@NonNull
@ColumnInfo(name = "account_name")
private String accountName;
@ColumnInfo(name = "instance_name")
private String name;
@ColumnInfo(name = "icon")
private String icon;
public BlockedInstanceData(int id, String domain, String name, String icon, String accountName) {
this.id = id;
this.domain = domain;
this.icon = icon;
this.name = name;
this.accountName = accountName;
}
public int getId() {
return id;
}
public String getDomain() {
return domain;
}
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
public String getName() {
return name;
}
public String getIcon() {
return icon;
}
}

View File

@ -0,0 +1,47 @@
package eu.toldi.infinityforlemmy.blockedinstances;
import android.os.AsyncTask;
import androidx.lifecycle.LiveData;
import java.util.List;
import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
public class BlockedInstanceRepository {
private BlockedInstanceDao blockedInstanceDao;
private String mAccountName;
BlockedInstanceRepository(RedditDataRoomDatabase redditDataRoomDatabase, String accountName) {
blockedInstanceDao = redditDataRoomDatabase.blockedInstanceDao();
mAccountName = accountName;
}
LiveData<List<BlockedInstanceData>> getAllBlockedInstancesWithSearchQuery(String searchQuery) {
return blockedInstanceDao.getAllBlockedInstancesWithSearchQuery(mAccountName, searchQuery);
}
LiveData<List<BlockedInstanceData>> getAllFavoriteSubscribedInstancesWithSearchQuery(String searchQuery) {
return blockedInstanceDao.getAllBlockedInstancesWithSearchQuery(mAccountName, searchQuery);
}
public void insert(BlockedInstanceData BlockedInstanceData) {
new BlockedInstanceRepository.insertAsyncTask(blockedInstanceDao).execute(BlockedInstanceData);
}
private static class insertAsyncTask extends AsyncTask<BlockedInstanceData, Void, Void> {
private BlockedInstanceDao mAsyncTaskDao;
insertAsyncTask(BlockedInstanceDao dao) {
mAsyncTaskDao = dao;
}
@Override
protected Void doInBackground(final BlockedInstanceData... params) {
mAsyncTaskDao.insert(params[0]);
return null;
}
}
}

View File

@ -0,0 +1,61 @@
package eu.toldi.infinityforlemmy.blockedinstances;
import android.app.Application;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Transformations;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import java.util.List;
import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
public class BlockedInstanceViewModel extends AndroidViewModel {
private BlockedInstanceRepository blockedInstanceRepository;
private LiveData<List<BlockedInstanceData>> mAllSubscribedInstances;
private MutableLiveData<String> searchQueryLiveData;
public BlockedInstanceViewModel(Application application, RedditDataRoomDatabase redditDataRoomDatabase, String accountName) {
super(application);
blockedInstanceRepository = new BlockedInstanceRepository(redditDataRoomDatabase, accountName);
searchQueryLiveData = new MutableLiveData<>();
searchQueryLiveData.postValue("");
mAllSubscribedInstances = Transformations.switchMap(searchQueryLiveData, searchQuery -> blockedInstanceRepository.getAllFavoriteSubscribedInstancesWithSearchQuery(searchQuery));
}
public LiveData<List<BlockedInstanceData>> getAllSubscribedInstances() {
return mAllSubscribedInstances;
}
public void insert(BlockedInstanceData BlockedInstanceData) {
blockedInstanceRepository.insert(BlockedInstanceData);
}
public void setSearchQuery(String searchQuery) {
searchQueryLiveData.postValue(searchQuery);
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
private Application mApplication;
private RedditDataRoomDatabase mRedditDataRoomDatabase;
private String mAccountName;
public Factory(Application application, RedditDataRoomDatabase redditDataRoomDatabase, String accountName) {
mApplication = application;
mRedditDataRoomDatabase = redditDataRoomDatabase;
mAccountName = accountName;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
return (T) new BlockedInstanceViewModel(mApplication, mRedditDataRoomDatabase, mAccountName);
}
}
}

View File

@ -0,0 +1,173 @@
package eu.toldi.infinityforlemmy.fragments;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestManager;
import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife;
import eu.toldi.infinityforlemmy.FragmentCommunicator;
import eu.toldi.infinityforlemmy.Infinity;
import eu.toldi.infinityforlemmy.R;
import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
import eu.toldi.infinityforlemmy.activities.BaseActivity;
import eu.toldi.infinityforlemmy.activities.BlockedThingListingActivity;
import eu.toldi.infinityforlemmy.adapters.BlockedInstancesRecyclerViewAdapter;
import eu.toldi.infinityforlemmy.blockedinstances.BlockedInstanceViewModel;
import eu.toldi.infinityforlemmy.customtheme.CustomThemeWrapper;
import eu.toldi.infinityforlemmy.customviews.LinearLayoutManagerBugFixed;
import eu.toldi.infinityforlemmy.utils.SharedPreferencesUtils;
import me.zhanghai.android.fastscroll.FastScrollerBuilder;
import retrofit2.Retrofit;
public class BlockedInstancesListingFragment extends Fragment implements FragmentCommunicator {
public static final String EXTRA_ACCOUNT_NAME = "EAN";
public static final String EXTRA_ACCESS_TOKEN = "EAT";
@BindView(R.id.swipe_refresh_layout_followed_users_listing_fragment)
SwipeRefreshLayout mSwipeRefreshLayout;
@BindView(R.id.recycler_view_followed_users_listing_fragment)
RecyclerView mRecyclerView;
@BindView(R.id.no_subscriptions_linear_layout_followed_users_listing_fragment)
LinearLayout mLinearLayout;
@BindView(R.id.no_subscriptions_image_view_followed_users_listing_fragment)
ImageView mImageView;
@BindView(R.id.error_text_view_followed_users_listing_fragment)
TextView mErrorTextView;
@Inject
@Named("oauth")
Retrofit mOauthRetrofit;
@Inject
@Named("default")
SharedPreferences mSharedPreferences;
@Inject
RedditDataRoomDatabase mRedditDataRoomDatabase;
@Inject
CustomThemeWrapper mCustomThemeWrapper;
@Inject
Executor mExecutor;
BlockedInstanceViewModel blockedInstanceViewModel;
private BaseActivity mActivity;
private RequestManager mGlide;
private LinearLayoutManagerBugFixed mLinearLayoutManager;
public BlockedInstancesListingFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_followed_users_listing, container, false);
ButterKnife.bind(this, rootView);
((Infinity) mActivity.getApplication()).getAppComponent().inject(this);
applyTheme();
Resources resources = getResources();
if ((mActivity instanceof BaseActivity && ((BaseActivity) mActivity).isImmersiveInterface())) {
mRecyclerView.setPadding(0, 0, 0, ((BaseActivity) mActivity).getNavBarHeight());
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& mSharedPreferences.getBoolean(SharedPreferencesUtils.IMMERSIVE_INTERFACE_KEY, true)) {
int navBarResourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
if (navBarResourceId > 0) {
mRecyclerView.setPadding(0, 0, 0, resources.getDimensionPixelSize(navBarResourceId));
}
}
mGlide = Glide.with(this);
String accessToken = getArguments().getString(EXTRA_ACCESS_TOKEN);
if (accessToken == null) {
mSwipeRefreshLayout.setEnabled(false);
}
mLinearLayoutManager = new LinearLayoutManagerBugFixed(mActivity);
mRecyclerView.setLayoutManager(mLinearLayoutManager);
BlockedInstancesRecyclerViewAdapter adapter = new BlockedInstancesRecyclerViewAdapter(mActivity,
mExecutor, mOauthRetrofit, mRedditDataRoomDatabase, mCustomThemeWrapper, accessToken);
mRecyclerView.setAdapter(adapter);
new FastScrollerBuilder(mRecyclerView).useMd2Style().build();
blockedInstanceViewModel = new ViewModelProvider(this,
new BlockedInstanceViewModel.Factory(mActivity.getApplication(), mRedditDataRoomDatabase, getArguments().getString(EXTRA_ACCOUNT_NAME)))
.get(BlockedInstanceViewModel.class);
blockedInstanceViewModel.getAllSubscribedInstances().observe(getViewLifecycleOwner(), blockedInstanceData -> {
mSwipeRefreshLayout.setRefreshing(false);
if (blockedInstanceData == null || blockedInstanceData.size() == 0) {
mRecyclerView.setVisibility(View.GONE);
mLinearLayout.setVisibility(View.VISIBLE);
mGlide.load(R.drawable.error_image).into(mImageView);
mErrorTextView.setText(R.string.no_blocked_instances);
} else {
mLinearLayout.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
mGlide.clear(mImageView);
}
adapter.blockedInstances(blockedInstanceData);
});
return rootView;
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
mActivity = (BaseActivity) context;
}
@Override
public void stopRefreshProgressbar() {
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void applyTheme() {
if (mActivity instanceof BlockedThingListingActivity) {
mSwipeRefreshLayout.setOnRefreshListener(() -> ((BlockedThingListingActivity) mActivity).loadBlocks(true));
mSwipeRefreshLayout.setProgressBackgroundColorSchemeColor(mCustomThemeWrapper.getCircularProgressBarBackground());
mSwipeRefreshLayout.setColorSchemeColors(mCustomThemeWrapper.getColorAccent());
} else {
mSwipeRefreshLayout.setEnabled(false);
}
mErrorTextView.setTextColor(mCustomThemeWrapper.getSecondaryTextColor());
if (mActivity.typeface != null) {
mErrorTextView.setTypeface(mActivity.typeface);
}
}
public void goBackToTop() {
if (mLinearLayoutManager != null) {
mLinearLayoutManager.scrollToPositionWithOffset(0, 0);
}
}
public void changeSearchQuery(String searchQuery) {
blockedInstanceViewModel.setSearchQuery(searchQuery);
}
}

View File

@ -1323,4 +1323,6 @@
<string name="token_expired_message">"Your token has been expired. As Eternity does not store your password, you need to manually log back in! "</string>
<string name="sort_most_comments">Most Comments</string>
<string name="sort_new_comments">New Comments</string>
<string name="instances">Instances</string>
<string name="no_blocked_instances">No blocked instances</string>
</resources>