parent
b09aab4a1d
commit
3cdcffe03d
|
@ -0,0 +1,10 @@
|
||||||
|
package org.joinmastodon.android.api.requests.announcements;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
|
||||||
|
public class DismissAnnouncement extends MastodonAPIRequest<Object>{
|
||||||
|
public DismissAnnouncement(String id){
|
||||||
|
super(HttpMethod.POST, "/announcements/" + id + "/dismiss", Object.class);
|
||||||
|
setRequestBody(new Object());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package org.joinmastodon.android.api.requests.announcements;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.Announcement;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class GetAnnouncements extends MastodonAPIRequest<List<Announcement>> {
|
||||||
|
public GetAnnouncements(boolean withDismissed) {
|
||||||
|
super(MastodonAPIRequest.HttpMethod.GET, "/announcements", new TypeToken<>(){});
|
||||||
|
addQueryParameter("with_dismissed", withDismissed ? "true" : "false");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package org.joinmastodon.android.fragments;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
|
import com.squareup.otto.Subscribe;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.E;
|
||||||
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.requests.announcements.GetAnnouncements;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.GetScheduledStatuses;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.ScheduledStatusCreatedEvent;
|
||||||
|
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
|
||||||
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Announcement;
|
||||||
|
import org.joinmastodon.android.model.HeaderPaginationList;
|
||||||
|
import org.joinmastodon.android.model.Instance;
|
||||||
|
import org.joinmastodon.android.model.ScheduledStatus;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
|
||||||
|
import org.joinmastodon.android.ui.text.HtmlParser;
|
||||||
|
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||||
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import me.grishka.appkit.Nav;
|
||||||
|
import me.grishka.appkit.api.PaginatedList;
|
||||||
|
import me.grishka.appkit.api.SimpleCallback;
|
||||||
|
|
||||||
|
public class AnnouncementsFragment extends BaseStatusListFragment<Announcement> {
|
||||||
|
private Instance instance;
|
||||||
|
private AccountSession session;
|
||||||
|
private List<String> unreadIDs = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAttach(Activity activity){
|
||||||
|
super.onAttach(activity);
|
||||||
|
setTitle(R.string.sk_announcements);
|
||||||
|
session = AccountSessionManager.getInstance().getAccount(accountID);
|
||||||
|
instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
||||||
|
loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<StatusDisplayItem> buildDisplayItems(Announcement a) {
|
||||||
|
if(TextUtils.isEmpty(a.content)) return List.of();
|
||||||
|
Account instanceUser = new Account();
|
||||||
|
instanceUser.id = instanceUser.acct = instanceUser.username = session.domain;
|
||||||
|
instanceUser.displayName = instance.title;
|
||||||
|
instanceUser.url = "https://"+session.domain+"/about";
|
||||||
|
instanceUser.avatar = instanceUser.avatarStatic = instance.thumbnail;
|
||||||
|
instanceUser.emojis = List.of();
|
||||||
|
Status fakeStatus = a.toStatus();
|
||||||
|
return List.of(
|
||||||
|
HeaderStatusDisplayItem.fromAnnouncement(a, fakeStatus, instanceUser, this, accountID, this::onMarkAsRead),
|
||||||
|
new TextStatusDisplayItem(a.id, HtmlParser.parse(a.content, a.emojis, a.mentions, a.tags, accountID), this, fakeStatus)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMarkAsRead(String id) {
|
||||||
|
if (unreadIDs == null) return;
|
||||||
|
unreadIDs.remove(id);
|
||||||
|
if (unreadIDs.size() == 0) setResult(true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addAccountToKnown(Announcement s) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onItemClick(String id) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDataLoaded(List<Announcement> d, boolean more) {
|
||||||
|
unreadIDs = d.stream().filter(a -> !a.read).map(a -> a.id).collect(Collectors.toList());
|
||||||
|
super.onDataLoaded(d, more);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doLoadData(int offset, int count){
|
||||||
|
currentRequest=new GetAnnouncements(true)
|
||||||
|
.setCallback(new SimpleCallback<>(this){
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Announcement> result){
|
||||||
|
onDataLoaded(result, false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.exec(accountID);
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,10 +29,12 @@ import com.squareup.otto.Subscribe;
|
||||||
import org.joinmastodon.android.E;
|
import org.joinmastodon.android.E;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
|
import org.joinmastodon.android.api.requests.announcements.GetAnnouncements;
|
||||||
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
|
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
|
import org.joinmastodon.android.model.Announcement;
|
||||||
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
||||||
import org.joinmastodon.android.model.Filter;
|
import org.joinmastodon.android.model.Filter;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
|
@ -56,11 +58,14 @@ import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
|
|
||||||
public class HomeTimelineFragment extends StatusListFragment{
|
public class HomeTimelineFragment extends StatusListFragment{
|
||||||
|
private static final int ANNOUNCEMENTS_RESULT = 654;
|
||||||
|
|
||||||
private ImageButton fab;
|
private ImageButton fab;
|
||||||
private ImageView toolbarLogo;
|
private ImageView toolbarLogo;
|
||||||
private Button toolbarShowNewPostsBtn;
|
private Button toolbarShowNewPostsBtn;
|
||||||
private boolean newPostsBtnShown;
|
private boolean newPostsBtnShown;
|
||||||
private AnimatorSet currentNewPostsAnim;
|
private AnimatorSet currentNewPostsAnim;
|
||||||
|
private MenuItem announcements;
|
||||||
|
|
||||||
private String maxID;
|
private String maxID;
|
||||||
|
|
||||||
|
@ -126,16 +131,40 @@ public class HomeTimelineFragment extends StatusListFragment{
|
||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
|
||||||
inflater.inflate(R.menu.home, menu);
|
inflater.inflate(R.menu.home, menu);
|
||||||
|
announcements = menu.findItem(R.id.announcements);
|
||||||
|
|
||||||
|
new GetAnnouncements(false).setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(List<Announcement> result) {
|
||||||
|
boolean hasUnread = result.stream().anyMatch(a -> !a.read);
|
||||||
|
announcements.setIcon(hasUnread ? R.drawable.ic_announcements_24_badged : R.drawable.ic_fluent_megaphone_24_regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(getActivity());
|
||||||
|
}
|
||||||
|
}).exec(accountID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item){
|
public boolean onOptionsItemSelected(MenuItem item){
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", accountID);
|
args.putString("account", accountID);
|
||||||
Nav.go(getActivity(), SettingsFragment.class, args);
|
if (item.getItemId() == R.id.settings) Nav.go(getActivity(), SettingsFragment.class, args);
|
||||||
|
if (item.getItemId() == R.id.announcements) {
|
||||||
|
Nav.goForResult(getActivity(), AnnouncementsFragment.class, args, ANNOUNCEMENTS_RESULT, this);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFragmentResult(int reqCode, boolean noMoreUnread, Bundle result){
|
||||||
|
if (reqCode == ANNOUNCEMENTS_RESULT && noMoreUnread) {
|
||||||
|
announcements.setIcon(R.drawable.ic_fluent_megaphone_24_regular);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onConfigurationChanged(Configuration newConfig){
|
public void onConfigurationChanged(Configuration newConfig){
|
||||||
super.onConfigurationChanged(newConfig);
|
super.onConfigurationChanged(newConfig);
|
||||||
|
|
|
@ -36,10 +36,10 @@ import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.UsableRecyclerView;
|
import me.grishka.appkit.views.UsableRecyclerView;
|
||||||
|
|
||||||
public class CustomLoginFragment extends InstanceCatalogFragment {
|
public class CustomWelcomeFragment extends InstanceCatalogFragment {
|
||||||
private View headerView;
|
private View headerView;
|
||||||
|
|
||||||
public CustomLoginFragment() {
|
public CustomWelcomeFragment() {
|
||||||
super(R.layout.fragment_welcome_custom, 1);
|
super(R.layout.fragment_welcome_custom, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ public class CustomLoginFragment extends InstanceCatalogFragment {
|
||||||
dataLoaded();
|
dataLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Override
|
@Override
|
||||||
protected void onUpdateToolbar(){
|
protected void onUpdateToolbar(){
|
||||||
// super.onUpdateToolbar();
|
super.onUpdateToolbar();
|
||||||
|
|
||||||
if (!canGoBack()) {
|
if (!canGoBack()) {
|
||||||
ImageView toolbarLogo=new ImageView(getActivity());
|
ImageView toolbarLogo=new ImageView(getActivity());
|
||||||
|
@ -137,9 +137,11 @@ public class CustomLoginFragment extends InstanceCatalogFragment {
|
||||||
|
|
||||||
headerView.findViewById(R.id.more).setVisibility(View.GONE);
|
headerView.findViewById(R.id.more).setVisibility(View.GONE);
|
||||||
headerView.findViewById(R.id.visibility).setVisibility(View.GONE);
|
headerView.findViewById(R.id.visibility).setVisibility(View.GONE);
|
||||||
((TextView) headerView.findViewById(R.id.username)).setText("@moshidon");
|
headerView.findViewById(R.id.separator).setVisibility(View.GONE);
|
||||||
|
headerView.findViewById(R.id.timestamp).setVisibility(View.GONE);
|
||||||
|
headerView.findViewById(R.id.unread_indicator).setVisibility(View.GONE);
|
||||||
|
((TextView) headerView.findViewById(R.id.username)).setText(R.string.sk_app_username);
|
||||||
((TextView) headerView.findViewById(R.id.name)).setText(R.string.sk_app_name);
|
((TextView) headerView.findViewById(R.id.name)).setText(R.string.sk_app_name);
|
||||||
((TextView) headerView.findViewById(R.id.timestamp)).setText(R.string.time_now);
|
|
||||||
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
|
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
|
||||||
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);
|
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);
|
||||||
|
|
||||||
|
@ -204,11 +206,6 @@ public class CustomLoginFragment extends InstanceCatalogFragment {
|
||||||
|
|
||||||
public InstanceViewHolder(){
|
public InstanceViewHolder(){
|
||||||
super(getActivity(), R.layout.item_instance_custom, list);
|
super(getActivity(), R.layout.item_instance_custom, list);
|
||||||
|
|
||||||
// itemView.setPadding(V.dp(16), V.dp(16), V.dp(16), V.dp(16));
|
|
||||||
// TypedValue value = new TypedValue();
|
|
||||||
// getActivity().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, value, true);
|
|
||||||
// itemView.setBackground(getActivity().getTheme().getDrawable(R.drawable.bg_search_field));
|
|
||||||
title=findViewById(R.id.title);
|
title=findViewById(R.id.title);
|
||||||
description=findViewById(R.id.description);
|
description=findViewById(R.id.description);
|
||||||
userCount=findViewById(R.id.user_count);
|
userCount=findViewById(R.id.user_count);
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package org.joinmastodon.android.model;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.RequiredField;
|
||||||
|
import org.parceler.Parcel;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Parcel
|
||||||
|
public class Announcement extends BaseModel implements DisplayItemsParent {
|
||||||
|
@RequiredField
|
||||||
|
public String id;
|
||||||
|
@RequiredField
|
||||||
|
public String content;
|
||||||
|
public Instant startsAt;
|
||||||
|
public Instant endsAt;
|
||||||
|
public boolean published;
|
||||||
|
public boolean allDay;
|
||||||
|
public Instant publishedAt;
|
||||||
|
public Instant updatedAt;
|
||||||
|
public boolean read;
|
||||||
|
public List<Emoji> emojis;
|
||||||
|
public List<Mention> mentions;
|
||||||
|
public List<Hashtag> tags;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Announcement{" +
|
||||||
|
"id='" + id + '\'' +
|
||||||
|
", content='" + content + '\'' +
|
||||||
|
", startsAt=" + startsAt +
|
||||||
|
", endsAt=" + endsAt +
|
||||||
|
", published=" + published +
|
||||||
|
", allDay=" + allDay +
|
||||||
|
", publishedAt=" + publishedAt +
|
||||||
|
", updatedAt=" + updatedAt +
|
||||||
|
", read=" + read +
|
||||||
|
", emojis=" + emojis +
|
||||||
|
", mentions=" + mentions +
|
||||||
|
", tags=" + tags +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
public Status toStatus() {
|
||||||
|
Status s = new Status();
|
||||||
|
s.id = id;
|
||||||
|
s.mediaAttachments = List.of();
|
||||||
|
s.createdAt = startsAt != null ? startsAt : publishedAt;
|
||||||
|
if (updatedAt != null) s.editedAt = updatedAt;
|
||||||
|
s.content = s.text = content;
|
||||||
|
s.spoilerText = "";
|
||||||
|
s.visibility = StatusPrivacy.PUBLIC;
|
||||||
|
s.mentions = List.of();
|
||||||
|
s.tags = List.of();
|
||||||
|
s.emojis = List.of();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getID() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import android.widget.Toast;
|
||||||
import org.joinmastodon.android.GlobalUserPreferences;
|
import org.joinmastodon.android.GlobalUserPreferences;
|
||||||
import org.joinmastodon.android.R;
|
import org.joinmastodon.android.R;
|
||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||||
|
import org.joinmastodon.android.api.requests.announcements.DismissAnnouncement;
|
||||||
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusSourceText;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusSourceText;
|
||||||
import org.joinmastodon.android.api.session.AccountSession;
|
import org.joinmastodon.android.api.session.AccountSession;
|
||||||
|
@ -35,6 +36,7 @@ import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
|
import org.joinmastodon.android.model.Announcement;
|
||||||
import org.joinmastodon.android.model.Attachment;
|
import org.joinmastodon.android.model.Attachment;
|
||||||
import org.joinmastodon.android.model.Notification;
|
import org.joinmastodon.android.model.Notification;
|
||||||
import org.joinmastodon.android.model.Relationship;
|
import org.joinmastodon.android.model.Relationship;
|
||||||
|
@ -52,6 +54,7 @@ import java.time.format.FormatStyle;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import me.grishka.appkit.Nav;
|
import me.grishka.appkit.Nav;
|
||||||
import me.grishka.appkit.api.APIRequest;
|
import me.grishka.appkit.api.APIRequest;
|
||||||
|
@ -75,6 +78,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
private String extraText;
|
private String extraText;
|
||||||
private Notification notification;
|
private Notification notification;
|
||||||
private ScheduledStatus scheduledStatus;
|
private ScheduledStatus scheduledStatus;
|
||||||
|
private Announcement announcement;
|
||||||
|
private Consumer<String> consumeReadAnnouncement;
|
||||||
|
|
||||||
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText, Notification notification, ScheduledStatus scheduledStatus){
|
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText, Notification notification, ScheduledStatus scheduledStatus){
|
||||||
super(parentID, parentFragment);
|
super(parentID, parentFragment);
|
||||||
|
@ -103,6 +108,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
this.extraText=extraText;
|
this.extraText=extraText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HeaderStatusDisplayItem fromAnnouncement(Announcement a, Status fakeStatus, Account instanceUser, BaseStatusListFragment parentFragment, String accountID, Consumer<String> consumeReadID) {
|
||||||
|
HeaderStatusDisplayItem item = new HeaderStatusDisplayItem(a.id, instanceUser, a.startsAt, parentFragment, accountID, fakeStatus, null, null, null);
|
||||||
|
item.announcement = a;
|
||||||
|
item.consumeReadAnnouncement = consumeReadID;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type getType(){
|
public Type getType(){
|
||||||
return Type.HEADER;
|
return Type.HEADER;
|
||||||
|
@ -122,8 +134,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||||
private final TextView name, username, timestamp, extraText;
|
private final TextView name, username, timestamp, extraText, separator;
|
||||||
private final ImageView avatar, more, visibility, deleteNotification;
|
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator;
|
||||||
private final PopupMenu optionsMenu;
|
private final PopupMenu optionsMenu;
|
||||||
private Relationship relationship;
|
private Relationship relationship;
|
||||||
private APIRequest<?> currentRelationshipRequest;
|
private APIRequest<?> currentRelationshipRequest;
|
||||||
|
@ -139,11 +151,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
super(activity, R.layout.display_item_header, parent);
|
super(activity, R.layout.display_item_header, parent);
|
||||||
name=findViewById(R.id.name);
|
name=findViewById(R.id.name);
|
||||||
username=findViewById(R.id.username);
|
username=findViewById(R.id.username);
|
||||||
|
separator=findViewById(R.id.separator);
|
||||||
timestamp=findViewById(R.id.timestamp);
|
timestamp=findViewById(R.id.timestamp);
|
||||||
avatar=findViewById(R.id.avatar);
|
avatar=findViewById(R.id.avatar);
|
||||||
more=findViewById(R.id.more);
|
more=findViewById(R.id.more);
|
||||||
visibility=findViewById(R.id.visibility);
|
visibility=findViewById(R.id.visibility);
|
||||||
deleteNotification=findViewById(R.id.delete_notification);
|
deleteNotification=findViewById(R.id.delete_notification);
|
||||||
|
unreadIndicator=findViewById(R.id.unread_indicator);
|
||||||
extraText=findViewById(R.id.extra_text);
|
extraText=findViewById(R.id.extra_text);
|
||||||
avatar.setOnClickListener(this::onAvaClick);
|
avatar.setOnClickListener(this::onAvaClick);
|
||||||
avatar.setOutlineProvider(roundCornersOutline);
|
avatar.setOutlineProvider(roundCornersOutline);
|
||||||
|
@ -268,6 +282,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
public void onBind(HeaderStatusDisplayItem item){
|
public void onBind(HeaderStatusDisplayItem item){
|
||||||
name.setText(item.parsedName);
|
name.setText(item.parsedName);
|
||||||
username.setText('@'+item.user.acct);
|
username.setText('@'+item.user.acct);
|
||||||
|
separator.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
|
||||||
username.setCompoundDrawablesWithIntrinsicBounds(item.user.bot ? R.drawable.ic_fluent_bot_24_filled : 0, 0, 0, 0);
|
username.setCompoundDrawablesWithIntrinsicBounds(item.user.bot ? R.drawable.ic_fluent_bot_24_filled : 0, 0, 0, 0);
|
||||||
|
|
||||||
|
@ -278,10 +294,14 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.getDefault());
|
||||||
timestamp.setText(item.scheduledStatus.scheduledAt.atZone(ZoneId.systemDefault()).format(formatter));
|
timestamp.setText(item.scheduledStatus.scheduledAt.atZone(ZoneId.systemDefault()).format(formatter));
|
||||||
}
|
}
|
||||||
else if(item.status==null || item.status.editedAt==null)
|
else if ((item.status==null || item.status.editedAt==null) && item.createdAt != null)
|
||||||
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
||||||
else
|
else if (item.status != null && item.status.editedAt != null)
|
||||||
timestamp.setText(item.parentFragment.getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(itemView.getContext(), item.status.editedAt)));
|
timestamp.setText(item.parentFragment.getString(R.string.edited_timestamp, UiUtils.formatRelativeTimestamp(itemView.getContext(), item.status.editedAt)));
|
||||||
|
else {
|
||||||
|
separator.setVisibility(View.GONE);
|
||||||
|
timestamp.setText("");
|
||||||
|
}
|
||||||
visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE);
|
visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE);
|
||||||
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
|
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
|
||||||
if(item.hasVisibilityToggle){
|
if(item.hasVisibilityToggle){
|
||||||
|
@ -305,6 +325,42 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
currentRelationshipRequest.cancel();
|
currentRelationshipRequest.cancel();
|
||||||
}
|
}
|
||||||
relationship=null;
|
relationship=null;
|
||||||
|
|
||||||
|
String desc;
|
||||||
|
if (item.announcement != null) {
|
||||||
|
if (unreadIndicator.getVisibility() == View.GONE) {
|
||||||
|
more.setAlpha(0f);
|
||||||
|
unreadIndicator.setAlpha(0f);
|
||||||
|
unreadIndicator.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
float alpha = item.announcement.read ? 0 : 1;
|
||||||
|
more.setImageResource(R.drawable.ic_fluent_checkmark_20_filled);
|
||||||
|
desc = item.parentFragment.getString(R.string.sk_mark_as_read);
|
||||||
|
more.animate().alpha(alpha);
|
||||||
|
unreadIndicator.animate().alpha(alpha);
|
||||||
|
more.setOnClickListener(v -> {
|
||||||
|
new DismissAnnouncement(item.announcement.id).setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Object o) {
|
||||||
|
item.consumeReadAnnouncement.accept(item.announcement.id);
|
||||||
|
item.announcement.read = true;
|
||||||
|
rebind();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(item.parentFragment.getActivity());
|
||||||
|
}
|
||||||
|
}).exec(item.accountID);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
more.setImageResource(R.drawable.ic_fluent_more_vertical_20_filled);
|
||||||
|
desc = item.parentFragment.getString(R.string.more_options);
|
||||||
|
more.setOnClickListener(this::onMoreClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
more.setContentDescription(desc);
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) more.setTooltipText(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -325,6 +381,10 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onAvaClick(View v){
|
private void onAvaClick(View v){
|
||||||
|
if (item.announcement != null) {
|
||||||
|
UiUtils.openURL(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.user.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
Bundle args=new Bundle();
|
Bundle args=new Bundle();
|
||||||
args.putString("account", item.accountID);
|
args.putString("account", item.accountID);
|
||||||
args.putParcelable("profileAccount", Parcels.wrap(item.user));
|
args.putParcelable("profileAccount", Parcels.wrap(item.user));
|
||||||
|
@ -356,6 +416,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateOptionsMenu(){
|
private void updateOptionsMenu(){
|
||||||
|
if (item.announcement != null) return;
|
||||||
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
boolean hasMultipleAccounts = AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1;
|
||||||
Menu menu=optionsMenu.getMenu();
|
Menu menu=optionsMenu.getMenu();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:drawable="@drawable/ic_fluent_megaphone_24_regular" android:left="2dp" android:right="2dp" android:top="2dp" android:bottom="2dp"/>
|
||||||
|
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<stroke android:color="?android:colorPrimary" android:width="2dp"/>
|
||||||
|
<solid android:color="?android:colorAccent"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
||||||
|
<path android:pathData="M7.032 13.907l-3.471-3.905C3.285 9.692 2.81 9.664 2.5 9.939 2.193 10.215 2.165 10.69 2.44 11l4 4.5c0.287 0.322 0.786 0.336 1.091 0.031l10.5-10.5c0.293-0.293 0.293-0.767 0-1.06-0.293-0.293-0.767-0.293-1.06 0l-9.938 9.937z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
||||||
|
<path android:pathData="M13 10c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||||
|
<path android:pathData="M21.907 5.622C21.969 5.83 22 6.046 22 6.263V17.74c0 1.242-1.007 2.25-2.25 2.25-0.217 0-0.433-0.032-0.641-0.094l-5.514-1.64C12.938 19.602 11.558 20.5 10 20.5c-2.142 0-3.891-1.683-3.995-3.8L6 16.5 5.999 16l-2.39-0.711C2.655 15.004 2 14.127 2 13.131V10.87c0-0.995 0.655-1.873 1.61-2.156l15.5-4.606c1.19-0.355 2.443 0.324 2.797 1.515zM7.499 16.445L7.5 16.499C7.5 17.88 8.62 19 10 19c0.885 0 1.678-0.464 2.124-1.179l-4.625-1.375zm12.037-10.9l-15.5 4.605C3.718 10.245 3.5 10.537 3.5 10.87v2.261c0 0.332 0.218 0.625 0.536 0.72l15.5 4.607c0.07 0.02 0.142 0.03 0.214 0.03 0.414 0 0.75-0.335 0.75-0.75V6.264c0-0.072-0.01-0.144-0.031-0.213-0.118-0.397-0.536-0.624-0.933-0.506z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,3 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
|
||||||
|
<path android:pathData="M10 6.5c-0.966 0-1.75-0.784-1.75-1.75S9.034 3 10 3s1.75 0.784 1.75 1.75S10.966 6.5 10 6.5zM10 17c-0.966 0-1.75-0.784-1.75-1.75S9.034 13.5 10 13.5s1.75 0.784 1.75 1.75S10.966 17 10 17zm-1.75-7c0 0.966 0.784 1.75 1.75 1.75s1.75-0.784 1.75-1.75S10.966 8.25 10 8.25 8.25 9.034 8.25 10z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||||
|
</vector>
|
|
@ -18,7 +18,7 @@
|
||||||
android:background="?android:selectableItemBackgroundBorderless"
|
android:background="?android:selectableItemBackgroundBorderless"
|
||||||
android:contentDescription="@string/more_options"
|
android:contentDescription="@string/more_options"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:src="@drawable/ic_post_more"
|
android:src="@drawable/ic_fluent_more_vertical_20_filled"
|
||||||
android:tint="?android:textColorSecondary" />
|
android:tint="?android:textColorSecondary" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
@ -47,6 +47,17 @@
|
||||||
android:src="@drawable/ic_visibility"
|
android:src="@drawable/ic_visibility"
|
||||||
android:tint="?android:textColorSecondary" />
|
android:tint="?android:textColorSecondary" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/unread_indicator"
|
||||||
|
android:layout_width="36dp"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginTop="-6dp"
|
||||||
|
android:layout_toStartOf="@id/visibility"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:tint="?android:colorAccent"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_fluent_circle_small_20_filled" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="46sp"
|
android:layout_width="46sp"
|
||||||
|
@ -61,7 +72,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="12dp"
|
android:layout_marginEnd="12dp"
|
||||||
android:layout_marginTop="2sp"
|
android:layout_marginTop="2sp"
|
||||||
android:layout_toStartOf="@id/visibility"
|
android:layout_toStartOf="@id/unread_indicator"
|
||||||
android:layout_toEndOf="@id/avatar"
|
android:layout_toEndOf="@id/avatar"
|
||||||
android:minHeight="24sp">
|
android:minHeight="24sp">
|
||||||
|
|
||||||
|
@ -94,7 +105,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_below="@id/name_wrap"
|
android:layout_below="@id/name_wrap"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:layout_toStartOf="@id/visibility"
|
android:layout_toStartOf="@id/unread_indicator"
|
||||||
android:layout_toEndOf="@id/avatar"
|
android:layout_toEndOf="@id/avatar"
|
||||||
android:layoutDirection="locale"
|
android:layoutDirection="locale"
|
||||||
android:minHeight="20sp"
|
android:minHeight="20sp"
|
||||||
|
|
|
@ -14,8 +14,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="16dp"
|
android:layout_marginHorizontal="16dp"
|
||||||
android:layout_marginVertical="12dp"
|
android:layout_marginVertical="12dp"
|
||||||
android:text="@string/sk_welcome_title"
|
android:text="@string/sk_welcome_title" />
|
||||||
/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
style="@style/m3_body_large"
|
style="@style/m3_body_large"
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/announcements"
|
||||||
|
android:icon="@drawable/ic_fluent_megaphone_24_regular"
|
||||||
|
android:showAsAction="always"
|
||||||
|
android:title="@string/sk_announcements" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/settings"
|
android:id="@+id/settings"
|
||||||
android:icon="@drawable/ic_fluent_settings_24_regular"
|
android:icon="@drawable/ic_fluent_settings_24_regular"
|
||||||
|
|
|
@ -137,9 +137,12 @@
|
||||||
<string name="sk_clear_recent_emoji">Clear recently used emoji</string>
|
<string name="sk_clear_recent_emoji">Clear recently used emoji</string>
|
||||||
<string name="sk_disable_relocate_publish_button_to_enable_customization">Disable "Relocate publish button" to allow customization</string>
|
<string name="sk_disable_relocate_publish_button_to_enable_customization">Disable "Relocate publish button" to allow customization</string>
|
||||||
<string name="sk_keep_only_latest_notification">Keep only latest notification</string>
|
<string name="sk_keep_only_latest_notification">Keep only latest notification</string>
|
||||||
|
<string name="sk_announcements">Announcements</string>
|
||||||
|
<string name="sk_mark_as_read">Mark as read</string>
|
||||||
|
|
||||||
<!-- accessibility labels-->
|
<!-- accessibility labels-->
|
||||||
<string name="sk_poll_option_add">Add new poll option</string>
|
<string name="sk_poll_option_add">Add new poll option</string>
|
||||||
<string name="sk_fab_compose">Compose</string>
|
<string name="sk_fab_compose">Compose</string>
|
||||||
<string name="sk_sending_error">Error publishing</string>
|
<string name="sk_sending_error">Error publishing</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in New Issue