Better sidebar for community pages

This commit is contained in:
Balazs Toldi 2023-08-20 21:31:40 +02:00
parent ce7c284c6b
commit 3c65bfcf1b
No known key found for this signature in database
GPG Key ID: 6C7D440036F99D58
10 changed files with 389 additions and 114 deletions

View File

@ -16,11 +16,11 @@ def getCommitVersionCode = { ->
}
android {
compileSdk 33
compileSdk 34
defaultConfig {
applicationId "eu.toldi.infinityforlemmy"
minSdk 21
targetSdk 33
targetSdk 34
versionCode 128
versionName "0.0.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@ -108,6 +108,7 @@ dependencies {
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.core:core-ktx:+'
def lifecycleVersion = "2.5.1"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycleVersion"

View File

@ -1691,6 +1691,7 @@ public class ViewSubredditDetailActivity extends BaseActivity implements SortTyp
bundle.putString(SidebarFragment.EXTRA_ACCESS_TOKEN, mAccessToken);
bundle.putString(SidebarFragment.EXTRA_SUBREDDIT_NAME, communityName);
bundle.putString(SidebarFragment.EXTRA_COMMUNITY_QUALIFIED_NAME, qualifiedName);
bundle.putBoolean(SidebarFragment.EXTRA_SHOW_STATISTICS, !showStatistics);
fragment.setArguments(bundle);
return fragment;
}

View File

@ -0,0 +1,20 @@
package eu.toldi.infinityforlemmy.adapters;
import eu.toldi.infinityforlemmy.activities.BaseActivity;
import eu.toldi.infinityforlemmy.customtheme.CustomThemeWrapper;
import eu.toldi.infinityforlemmy.user.BasicUserRecyclerViewAdapter;
public class ModeratorRecyclerViewAdapter extends BasicUserRecyclerViewAdapter {
private final int mModeratorColor;
public ModeratorRecyclerViewAdapter(BaseActivity activity, CustomThemeWrapper customThemeWrapper) {
super(activity, customThemeWrapper);
mModeratorColor = customThemeWrapper.getModerator();
}
@Override
protected int getUserNameTextColor() {
return mModeratorColor;
}
}

View File

@ -22,6 +22,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.evernote.android.state.State;
import com.google.android.material.card.MaterialCardView;
import java.util.concurrent.Executor;
@ -36,6 +37,7 @@ import eu.toldi.infinityforlemmy.RedditDataRoomDatabase;
import eu.toldi.infinityforlemmy.RetrofitHolder;
import eu.toldi.infinityforlemmy.activities.LinkResolverActivity;
import eu.toldi.infinityforlemmy.activities.ViewSubredditDetailActivity;
import eu.toldi.infinityforlemmy.adapters.ModeratorRecyclerViewAdapter;
import eu.toldi.infinityforlemmy.asynctasks.InsertSubredditData;
import eu.toldi.infinityforlemmy.bottomsheetfragments.CopyTextBottomSheetFragment;
import eu.toldi.infinityforlemmy.bottomsheetfragments.UrlMenuBottomSheetFragment;
@ -46,6 +48,7 @@ import eu.toldi.infinityforlemmy.markdown.MarkdownUtils;
import eu.toldi.infinityforlemmy.subreddit.FetchSubredditData;
import eu.toldi.infinityforlemmy.subreddit.SubredditData;
import eu.toldi.infinityforlemmy.subreddit.SubredditViewModel;
import eu.toldi.infinityforlemmy.user.BasicUserRecyclerViewAdapter;
import eu.toldi.infinityforlemmy.utils.LemmyUtils;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
@ -61,12 +64,17 @@ public class SidebarFragment extends Fragment {
public static final String EXTRA_SUBREDDIT_NAME = "ESN";
public static final String EXTRA_ACCESS_TOKEN = "EAT";
public static final String EXTRA_COMMUNITY_QUALIFIED_NAME = "ECQN";
public static final String EXTRA_SHOW_STATISTICS = "ESS";
public SubredditViewModel mSubredditViewModel;
@BindView(R.id.swipe_refresh_layout_sidebar_fragment)
SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.markdown_recycler_view_sidebar_fragment)
RecyclerView recyclerView;
@BindView(R.id.recycler_view_moderators_side_fragment)
RecyclerView moderatorsRecyclerView;
@BindView(R.id.subscriber_count_text_view_sidebar_fragment)
TextView nSubscribersTextView;
@BindView(R.id.active_user_count_text_view_sidebar_fragment)
@ -87,6 +95,19 @@ public class SidebarFragment extends Fragment {
@BindView(R.id.community_statistics_block_sidebar_fragment)
ConstraintLayout communityStatisticsBlock;
@BindView(R.id.moderators_text_view_sidebar_fragment)
TextView moderatorsTextView;
@BindView(R.id.moderators_card_sidebar_fragment)
MaterialCardView moderatorsCard;
@BindView(R.id.description_card_sidebar_fragment)
MaterialCardView descriptionCard;
@BindView(R.id.statistics_card_sidebar_fragment)
MaterialCardView statisticsCard;
@Inject
@Named("no_oauth")
RetrofitHolder mRetrofit;
@ -103,6 +124,8 @@ public class SidebarFragment extends Fragment {
private String mAccessToken;
private String subredditName;
private boolean mShowStatistics;
private String communityQualifiedName;
private LinearLayoutManagerBugFixed linearLayoutManager;
private int markdownColor;
@ -110,6 +133,7 @@ public class SidebarFragment extends Fragment {
@State
CommunityStats mCommunityStats;
private BasicUserRecyclerViewAdapter moderatorAdapter;
public SidebarFragment() {
// Required empty public constructor
@ -128,6 +152,7 @@ public class SidebarFragment extends Fragment {
mAccessToken = getArguments().getString(EXTRA_ACCESS_TOKEN);
subredditName = getArguments().getString(EXTRA_SUBREDDIT_NAME);
communityQualifiedName = getArguments().getString(EXTRA_COMMUNITY_QUALIFIED_NAME);
mShowStatistics = getArguments().getBoolean(EXTRA_SHOW_STATISTICS, true);
if (communityQualifiedName == null) {
Toast.makeText(activity, R.string.error_getting_community_name, Toast.LENGTH_SHORT).show();
return rootView;
@ -135,15 +160,26 @@ public class SidebarFragment extends Fragment {
swipeRefreshLayout.setProgressBackgroundColorSchemeColor(mCustomThemeWrapper.getCircularProgressBarBackground());
swipeRefreshLayout.setColorSchemeColors(mCustomThemeWrapper.getColorAccent());
int mCardViewBackgroundColor = mCustomThemeWrapper.getCardViewBackgroundColor();
int primaryTextColor = mCustomThemeWrapper.getPrimaryTextColor();
nSubscribersTextView.setTextColor(primaryTextColor);
nActiveUsersTextView.setTextColor(primaryTextColor);
nPostsTextView.setTextColor(primaryTextColor);
nCommentsTextView.setTextColor(primaryTextColor);
moderatorsTextView.setTextColor(primaryTextColor);
moderatorsTextView.setTypeface(activity.contentTypeface);
nSubscribersImageView.setColorFilter(mCustomThemeWrapper.getPrimaryTextColor(), PorterDuff.Mode.SRC_IN);
nActiveUsersImageView.setColorFilter(mCustomThemeWrapper.getPrimaryTextColor(), PorterDuff.Mode.SRC_IN);
nPostsImageView.setColorFilter(mCustomThemeWrapper.getPrimaryTextColor(), PorterDuff.Mode.SRC_IN);
nCommentsImageView.setColorFilter(mCustomThemeWrapper.getPrimaryTextColor(), PorterDuff.Mode.SRC_IN);
moderatorsCard.setCardBackgroundColor(mCardViewBackgroundColor);
descriptionCard.setCardBackgroundColor(mCardViewBackgroundColor);
if (mShowStatistics) {
statisticsCard.setCardBackgroundColor(mCardViewBackgroundColor);
} else {
statisticsCard.setVisibility(View.GONE);
}
markdownColor = mCustomThemeWrapper.getPrimaryTextColor();
int spoilerBackgroundColor = markdownColor | 0xFF000000;
@ -206,6 +242,11 @@ public class SidebarFragment extends Fragment {
}
});
moderatorsRecyclerView.setLayoutManager(new LinearLayoutManagerBugFixed(activity));
moderatorAdapter = new ModeratorRecyclerViewAdapter(activity,
mCustomThemeWrapper);
moderatorsRecyclerView.setAdapter(moderatorAdapter);
mSubredditViewModel = new ViewModelProvider(activity,
new SubredditViewModel.Factory(activity.getApplication(), mRedditDataRoomDatabase, LemmyUtils.qualifiedCommunityName2ActorId(communityQualifiedName)))
.get(SubredditViewModel.class);
@ -250,6 +291,7 @@ public class SidebarFragment extends Fragment {
public void onFetchSubredditDataSuccess(SubredditData subredditData, int nCurrentOnlineSubscribers) {
swipeRefreshLayout.setRefreshing(false);
mCommunityStats = subredditData.getCommunityStats();
moderatorAdapter.setUsers(subredditData.getModerators());
InsertSubredditData.insertSubredditData(mExecutor, new Handler(), mRedditDataRoomDatabase,
subredditData, () -> swipeRefreshLayout.setRefreshing(false));
}

View File

@ -16,7 +16,9 @@ import java.util.Locale;
import java.util.TimeZone;
import eu.toldi.infinityforlemmy.community.CommunityStats;
import eu.toldi.infinityforlemmy.user.BasicUserInfo;
import eu.toldi.infinityforlemmy.utils.JSONUtils;
import eu.toldi.infinityforlemmy.utils.LemmyUtils;
public class ParseSubredditData {
public static void parseSubredditData(String response, ParseSubredditDataListener parseSubredditDataListener) {
@ -80,7 +82,6 @@ public class ParseSubredditData {
int commentCount = counts.getInt("comments");
stats = new CommunityStats(subscribers, activeUserCount, postCount, commentCount);
}
return new SubredditData(id, name, title, description, removed, published, updated, deleted, isNSFW, actorId, local, iconUrl, bannerImageUrl, hidden, postingRestrictedToMods, instanceId, subscribers, blocked, stats);
}
@ -120,6 +121,16 @@ public class ParseSubredditData {
JSONObject data = jsonResponse.getJSONObject("community_view");
mNCurrentOnlineSubscribers = 0;// data.getInt(JSONUtils.ACTIVE_USER_COUNT_KEY);
subredditData = parseSubredditData(data, true);
JSONArray moderators = jsonResponse.getJSONArray("moderators");
for (int i = 0; i < moderators.length(); i++) {
JSONObject moderator = moderators.getJSONObject(i).getJSONObject("moderator");
int mod_id = moderator.getInt("id");
String mod_name = moderator.getString("name");
String mod_displayName = moderator.optString("display_name", mod_name);
String mod_qualified_name = LemmyUtils.actorID2FullName(moderator.getString("actor_id"));
String avatarUrl = moderator.optString("avatar", "");
subredditData.addModerator(new BasicUserInfo(mod_id, mod_name, mod_qualified_name, avatarUrl, mod_displayName));
}
} catch (JSONException e) {
parseFailed = true;
e.printStackTrace();

View File

@ -9,7 +9,11 @@ import androidx.room.Entity;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import java.util.ArrayList;
import java.util.List;
import eu.toldi.infinityforlemmy.community.CommunityStats;
import eu.toldi.infinityforlemmy.user.BasicUserInfo;
@Entity(tableName = "subreddits")
public class SubredditData implements Parcelable {
@ -76,6 +80,9 @@ public class SubredditData implements Parcelable {
@Ignore
private CommunityStats communityStats;
@Ignore
private List<BasicUserInfo> moderators = new ArrayList<>();
protected SubredditData(Parcel in) {
id = in.readInt();
name = in.readString();
@ -366,4 +373,12 @@ public class SubredditData implements Parcelable {
public void setCommunityStats(CommunityStats communityStats) {
this.communityStats = communityStats;
}
public List<BasicUserInfo> getModerators() {
return moderators;
}
public void addModerator(BasicUserInfo moderator) {
moderators.add(moderator);
}
}

View File

@ -0,0 +1,139 @@
package eu.toldi.infinityforlemmy.user;
import android.content.Intent;
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 butterknife.BindView;
import butterknife.ButterKnife;
import eu.toldi.infinityforlemmy.R;
import eu.toldi.infinityforlemmy.activities.BaseActivity;
import eu.toldi.infinityforlemmy.activities.ViewUserDetailActivity;
import eu.toldi.infinityforlemmy.customtheme.CustomThemeWrapper;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;
import me.zhanghai.android.fastscroll.PopupTextProvider;
import pl.droidsonroids.gif.GifImageView;
public class BasicUserRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements PopupTextProvider {
private static final int VIEW_TYPE_FAVORITE_USER_DIVIDER = 0;
private static final int VIEW_TYPE_FAVORITE_USER = 1;
private static final int VIEW_TYPE_USER_DIVIDER = 2;
private static final int VIEW_TYPE_USER = 3;
private List<BasicUserInfo> basicUserInfo;
private BaseActivity mActivity;
private RequestManager glide;
private int mPrimaryTextColor;
private int mSecondaryTextColor;
public BasicUserRecyclerViewAdapter(BaseActivity activity,
CustomThemeWrapper customThemeWrapper) {
mActivity = activity;
glide = Glide.with(activity);
mPrimaryTextColor = customThemeWrapper.getPrimaryTextColor();
mSecondaryTextColor = customThemeWrapper.getSecondaryTextColor();
}
@Override
public int getItemViewType(int position) {
return VIEW_TYPE_USER;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
return new UserViewHolder(LayoutInflater.from(viewGroup.getContext())
.inflate(R.layout.item_subscribed_thing, viewGroup, false));
}
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof UserViewHolder) {
if (!basicUserInfo.get(viewHolder.getBindingAdapterPosition()).getAvatar().equals("")) {
glide.load(basicUserInfo.get(viewHolder.getBindingAdapterPosition()).getAvatar())
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.error(glide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0))))
.into(((UserViewHolder) viewHolder).iconGifImageView);
} else {
glide.load(R.drawable.subreddit_default_icon)
.apply(RequestOptions.bitmapTransform(new RoundedCornersTransformation(72, 0)))
.into(((UserViewHolder) viewHolder).iconGifImageView);
}
((UserViewHolder) viewHolder).userNameTextView.setText(basicUserInfo.get(viewHolder.getBindingAdapterPosition()).getDisplayName());
}
}
@Override
public int getItemCount() {
if (basicUserInfo != null && basicUserInfo.size() > 0) {
return basicUserInfo.size();
}
return 0;
}
@Override
public void onViewRecycled(@NonNull RecyclerView.ViewHolder holder) {
if (holder instanceof UserViewHolder) {
glide.clear(((UserViewHolder) holder).iconGifImageView);
}
}
public void setUsers(List<BasicUserInfo> subscribedUsers) {
basicUserInfo = subscribedUsers;
notifyDataSetChanged();
}
@NonNull
@Override
public String getPopupText(int position) {
return basicUserInfo.get(position).getQualifiedName().substring(0, 1).toUpperCase();
}
protected int getUserNameTextColor() {
return mPrimaryTextColor;
}
protected class UserViewHolder 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 userNameTextView;
protected UserViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
if (mActivity.typeface != null) {
userNameTextView.setTypeface(mActivity.typeface);
}
userNameTextView.setTextColor(getUserNameTextColor());
itemView.setOnClickListener(view -> {
int position = getBindingAdapterPosition();
if (position >= 0 && basicUserInfo.size() > position) {
Intent intent = new Intent(mActivity, ViewUserDetailActivity.class);
intent.putExtra(ViewUserDetailActivity.EXTRA_USER_NAME_KEY, basicUserInfo.get(position).getDisplayName());
intent.putExtra(ViewUserDetailActivity.EXTRA_QUALIFIED_USER_NAME_KEY, basicUserInfo.get(position).getQualifiedName());
mActivity.startActivity(intent);
}
});
}
}
}

View File

@ -12,13 +12,52 @@
android:layout_height="wrap_content"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.card.MaterialCardView
android:id="@+id/moderators_card_sidebar_fragment"
style="?attr/materialCardViewElevatedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/moderators_text_view_sidebar_fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="@string/moderators"
android:textSize="16sp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_moderators_side_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle"
android:id="@+id/description_card_sidebar_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@ -39,6 +78,7 @@
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewElevatedStyle"
android:id="@+id/statistics_card_sidebar_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@ -51,8 +91,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone"
android:layout_marginBottom="16dp">
android:layout_marginBottom="16dp"
android:visibility="gone">
<ImageView
android:id="@+id/subscriber_count_image_view_sidebar_fragment"
@ -144,7 +184,12 @@
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<View
android:id="@+id/placeholder_view_sidebar_fragment"
android:layout_width="match_parent"
android:layout_height="150dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -1375,4 +1375,5 @@
<string name="settings_category_community_and_user_pages_title">Community and User pages</string>
<string name="settings_show_statistics">Show Statistics</string>
<string name="settings_show_post_and_comment_score">Show post and comment scores</string>
<string name="moderators">Moderators</string>
</resources>

View File

@ -9,7 +9,7 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.20'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files