From b8e3426a1e87df84ec129e3f7bbba9db81b1e0c7 Mon Sep 17 00:00:00 2001 From: Grishka Date: Wed, 9 Feb 2022 17:53:27 +0300 Subject: [PATCH] Profile about tab --- .../fragments/ProfileAboutFragment.java | 123 ++++++++++++++++++ .../android/fragments/ProfileFragment.java | 57 ++++++-- .../android/model/AccountField.java | 3 + .../displayitems/TextStatusDisplayItem.java | 14 +- .../android/ui/photoviewer/PhotoViewer.java | 1 + .../android/ui/text/LinkSpan.java | 9 +- .../ui/views/NestedRecyclerScrollView.java | 2 +- .../ic_fluent_arrow_left_24_regular.xml | 3 + .../main/res/layout/item_profile_about.xml | 28 ++++ mastodon/src/main/res/values/colors.xml | 1 + mastodon/src/main/res/values/strings.xml | 1 + mastodon/src/main/res/values/styles.xml | 30 +++-- 12 files changed, 235 insertions(+), 37 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileAboutFragment.java create mode 100644 mastodon/src/main/res/drawable/ic_fluent_arrow_left_24_regular.xml create mode 100644 mastodon/src/main/res/layout/item_profile_about.xml diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileAboutFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileAboutFragment.java new file mode 100644 index 00000000..b732afc1 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileAboutFragment.java @@ -0,0 +1,123 @@ +package org.joinmastodon.android.fragments; + +import android.app.Fragment; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.drawable.ShapeDrawable; +import android.graphics.drawable.shapes.RoundRectShape; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.TextView; + +import org.joinmastodon.android.R; +import org.joinmastodon.android.model.AccountField; +import org.joinmastodon.android.ui.views.LinkedTextView; + +import java.util.Collections; +import java.util.List; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import me.grishka.appkit.imageloader.ListImageLoaderWrapper; +import me.grishka.appkit.utils.BindableViewHolder; +import me.grishka.appkit.utils.V; +import me.grishka.appkit.views.UsableRecyclerView; + +public class ProfileAboutFragment extends Fragment{ + public UsableRecyclerView list; + private List fields=Collections.emptyList(); + private AboutAdapter adapter; + private Paint dividerPaint=new Paint(); + + public void setFields(List fields){ + this.fields=fields; + if(adapter!=null) + adapter.notifyDataSetChanged(); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){ + list=new UsableRecyclerView(getActivity()); + list.setId(R.id.list); + list.setLayoutManager(new LinearLayoutManager(getActivity())); + list.setAdapter(adapter=new AboutAdapter()); + int pad=V.dp(16); + list.setPadding(pad, pad, pad, pad); + list.setClipToPadding(false); + dividerPaint.setStyle(Paint.Style.STROKE); + dividerPaint.setStrokeWidth(V.dp(1)); + dividerPaint.setColor(getResources().getColor(R.color.gray_200)); + list.addItemDecoration(new RecyclerView.ItemDecoration(){ + @Override + public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){ + for(int i=0;i{ + public AboutAdapter(){ + super(null); + } + + @NonNull + @Override + public AboutViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ + return new AboutViewHolder(); + } + + @Override + public void onBindViewHolder(AboutViewHolder holder, int position){ + holder.bind(fields.get(position)); + super.onBindViewHolder(holder, position); + } + + @Override + public int getItemCount(){ + return fields.size(); + } + } + + private class AboutViewHolder extends BindableViewHolder{ + private TextView title; + private LinkedTextView value; + private ShapeDrawable background=new ShapeDrawable(); + + public AboutViewHolder(){ + super(getActivity(), R.layout.item_profile_about, list); + title=findViewById(R.id.title); + value=findViewById(R.id.value); + background.getPaint().setColor(getResources().getColor(R.color.gray_50)); + itemView.setBackground(background); + } + + @Override + public void onBind(AccountField item){ + title.setText(item.name); + value.setText(item.parsedValue); + boolean first=getAbsoluteAdapterPosition()==0, last=getAbsoluteAdapterPosition()==fields.size()-1; + float radius=V.dp(10); + float[] rad=new float[8]; + if(first) + rad[0]=rad[1]=rad[2]=rad[3]=radius; + if(last) + rad[4]=rad[5]=rad[6]=rad[7]=radius; + background.setShape(new RoundRectShape(rad, null, null)); + itemView.invalidateOutline(); + } + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index a50038d8..724916d1 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -4,7 +4,6 @@ import android.app.Activity; import android.app.Fragment; import android.content.Intent; import android.content.res.Configuration; -import android.graphics.Matrix; import android.graphics.Outline; import android.os.Bundle; import android.util.Log; @@ -28,6 +27,7 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships; import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses; import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.model.Account; +import org.joinmastodon.android.model.AccountField; import org.joinmastodon.android.model.Relationship; import org.joinmastodon.android.ui.drawables.CoverOverlayGradientDrawable; import org.joinmastodon.android.ui.tabs.TabLayout; @@ -38,6 +38,12 @@ import org.joinmastodon.android.ui.views.CoverImageView; import org.joinmastodon.android.ui.views.NestedRecyclerScrollView; import org.parceler.Parcels; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -63,16 +69,18 @@ public class ProfileFragment extends LoaderFragment{ private ViewPager2 pager; private NestedRecyclerScrollView scrollView; private AccountTimelineFragment postsFragment, postsWithRepliesFragment, mediaFragment; + private ProfileAboutFragment aboutFragment; private TabLayout tabbar; private SwipeRefreshLayout refreshLayout; private CoverOverlayGradientDrawable coverGradient=new CoverOverlayGradientDrawable(); - private Matrix coverMatrix=new Matrix(); private float titleTransY; private Account account; private String accountID; private Relationship relationship; private int statusBarHeight; + private boolean isOwnProfile; + private ArrayList fields=new ArrayList<>(); public ProfileFragment(){ super(R.layout.loader_fragment_overlay_toolbar); @@ -123,9 +131,11 @@ public class ProfileFragment extends LoaderFragment{ if(getArguments().containsKey("profileAccount")){ account=Parcels.unwrap(getArguments().getParcelable("profileAccount")); + isOwnProfile=AccountSessionManager.getInstance().isSelf(accountID, account); bindHeaderView(); dataLoaded(); - loadRelationship(); + if(!isOwnProfile) + loadRelationship(); } scrollView.setScrollableChildSupplier(this::getScrollableRecyclerView); @@ -157,6 +167,12 @@ public class ProfileFragment extends LoaderFragment{ }).attach(); cover.setForeground(coverGradient); + cover.setOutlineProvider(new ViewOutlineProvider(){ + @Override + public void getOutline(View view, Outline outline){ + outline.setEmpty(); + } + }); return sizeWrapper; } @@ -184,9 +200,12 @@ public class ProfileFragment extends LoaderFragment{ public void onPageSelected(int position){ if(position==0) return; - BaseRecyclerFragment page=getFragmentForPage(position); - if(!page.loaded && !page.isDataLoading()) - page.loadData(); + Fragment _page=getFragmentForPage(position); + if(_page instanceof BaseRecyclerFragment){ + BaseRecyclerFragment page=(BaseRecyclerFragment) _page; + if(!page.loaded && !page.isDataLoading()) + page.loadData(); + } } }); return true; @@ -235,6 +254,22 @@ public class ProfileFragment extends LoaderFragment{ }else{ actionButton.setVisibility(View.GONE); } + + fields.clear(); + + AccountField joined=new AccountField(); + joined.name=getString(R.string.profile_joined); + joined.parsedValue=joined.value=DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(LocalDateTime.ofInstant(account.createdAt, ZoneId.systemDefault())); + fields.add(joined); + + for(AccountField field:account.fields){ + field.parsedValue=HtmlParser.parse(field.value, account.emojis); + fields.add(field); + } + + if(aboutFragment!=null){ + aboutFragment.setFields(fields); + } } private void updateToolbar(){ @@ -334,11 +369,12 @@ public class ProfileFragment extends LoaderFragment{ } } - private BaseRecyclerFragment getFragmentForPage(int page){ + private Fragment getFragmentForPage(int page){ return switch(page){ case 0 -> postsFragment; case 1 -> postsWithRepliesFragment; case 2 -> mediaFragment; + case 3 -> aboutFragment; default -> throw new IllegalStateException(); }; } @@ -363,6 +399,11 @@ public class ProfileFragment extends LoaderFragment{ case 0 -> postsFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.DEFAULT, true); case 1 -> postsWithRepliesFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.INCLUDE_REPLIES, false); case 2 -> mediaFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.MEDIA, false); + case 3 -> { + aboutFragment=new ProfileAboutFragment(); + aboutFragment.setFields(fields); + yield aboutFragment; + } default -> throw new IllegalArgumentException(); }; getChildFragmentManager().beginTransaction().add(holder.itemView.getId(), fragment).commit(); @@ -370,7 +411,7 @@ public class ProfileFragment extends LoaderFragment{ @Override public int getItemCount(){ - return 3; + return 4; } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/AccountField.java b/mastodon/src/main/java/org/joinmastodon/android/model/AccountField.java index 5e55301d..4d9f2661 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/model/AccountField.java +++ b/mastodon/src/main/java/org/joinmastodon/android/model/AccountField.java @@ -2,6 +2,7 @@ package org.joinmastodon.android.model; import org.joinmastodon.android.api.RequiredField; import org.parceler.Parcel; +import org.parceler.Transient; import java.time.Instant; @@ -25,6 +26,8 @@ public class AccountField extends BaseModel{ */ public Instant verifiedAt; + public transient CharSequence parsedValue; + @Override public String toString(){ return "AccountField{"+ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java index 73e85ef8..dbc1eefa 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java @@ -22,7 +22,7 @@ import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.utils.BindableViewHolder; import me.grishka.appkit.utils.V; -public class TextStatusDisplayItem extends StatusDisplayItem implements LinkSpan.OnLinkClickListener{ +public class TextStatusDisplayItem extends StatusDisplayItem{ private CharSequence text; private ImageLoaderRequest[] emojiRequests; private Fragment parentFragment; @@ -37,10 +37,6 @@ public class TextStatusDisplayItem extends StatusDisplayItem implements LinkSpan for(int i=0; i UiUtils.launchWebBrowser(parentFragment.getActivity(), span.getLink()); - case HASHTAG, MENTION -> Toast.makeText(parentFragment.getActivity(), "Not implemented yet", Toast.LENGTH_SHORT).show(); - } - } - public static class Holder extends StatusDisplayItem.Holder implements ImageLoaderViewHolder{ private final LinkedTextView text; private CustomEmojiSpan[] emojiSpans; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java b/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java index e84cc3d9..5823de03 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/photoviewer/PhotoViewer.java @@ -323,6 +323,7 @@ public class PhotoViewer implements ZoomPanView.Listener{ params.height=item.getHeight(); wrap.setBackground(listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition())); if(itemView.isAttachedToWindow()){ + reset(); prepareAndStartPlayer(); } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java index 84f65b47..326d3d05 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java @@ -3,6 +3,9 @@ package org.joinmastodon.android.ui.text; import android.content.Context; import android.text.TextPaint; import android.text.style.CharacterStyle; +import android.widget.Toast; + +import org.joinmastodon.android.ui.utils.UiUtils; public class LinkSpan extends CharacterStyle { @@ -31,8 +34,10 @@ public class LinkSpan extends CharacterStyle { } public void onClick(Context context){ - if(listener!=null) - listener.onLinkClick(this); + switch(getType()){ + case URL -> UiUtils.launchWebBrowser(context, link); + case HASHTAG, MENTION -> Toast.makeText(context, "Not implemented yet", Toast.LENGTH_SHORT).show(); + } } public String getLink(){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestedRecyclerScrollView.java b/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestedRecyclerScrollView.java index 0d3f4734..8bad60d6 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestedRecyclerScrollView.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/views/NestedRecyclerScrollView.java @@ -52,7 +52,7 @@ public class NestedRecyclerScrollView extends CustomScrollView{ private boolean isScrolledToTop(RecyclerView rv) { final LinearLayoutManager lm = (LinearLayoutManager) rv.getLayoutManager(); return lm.findFirstVisibleItemPosition() == 0 - && lm.findViewByPosition(0).getTop() == 0; + && lm.findViewByPosition(0).getTop() == rv.getPaddingTop(); } public void setScrollableChildSupplier(Supplier scrollableChildSupplier){ diff --git a/mastodon/src/main/res/drawable/ic_fluent_arrow_left_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_arrow_left_24_regular.xml new file mode 100644 index 00000000..4b2678b4 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_arrow_left_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/item_profile_about.xml b/mastodon/src/main/res/layout/item_profile_about.xml new file mode 100644 index 00000000..c651590d --- /dev/null +++ b/mastodon/src/main/res/layout/item_profile_about.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/colors.xml b/mastodon/src/main/res/values/colors.xml index 0c615f23..4474f4e9 100644 --- a/mastodon/src/main/res/values/colors.xml +++ b/mastodon/src/main/res/values/colors.xml @@ -14,6 +14,7 @@ #CCF9FAFB #F9FAFB #F2F4F7 + #E4E7EC #282C37 #667085 diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index fb0f7c62..56d78973 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -66,4 +66,5 @@ %,d post %,d posts + Joined \ No newline at end of file diff --git a/mastodon/src/main/res/values/styles.xml b/mastodon/src/main/res/values/styles.xml index fd20d2f1..2bbd4068 100644 --- a/mastodon/src/main/res/values/styles.xml +++ b/mastodon/src/main/res/values/styles.xml @@ -15,6 +15,7 @@ @style/Theme.Mastodon.Toolbar @style/Widget.Mastodon.Button @style/Theme.Mastodon.Dialog.Alert + @drawable/ic_fluent_arrow_left_24_regular - - + + + +