Compare commits
17 Commits
v1.1.1-dev
...
v1.1.1-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde2e398a8 | ||
|
|
8d443b2051 | ||
|
|
33d4b678ed | ||
|
|
3becad1468 | ||
|
|
fad3ba3eae | ||
|
|
cb16f95878 | ||
|
|
4e833490ff | ||
|
|
04a973f7b0 | ||
|
|
0318169b74 | ||
|
|
972fb1e241 | ||
|
|
9beb04b01d | ||
|
|
a3bea6ad24 | ||
|
|
7996e4ee4a | ||
|
|
69c4bf4213 | ||
|
|
7cd5ca77f5 | ||
|
|
7e736d3cd3 | ||
|
|
f0cef2103f |
@@ -12,6 +12,7 @@ Learn more about this app in the [blog post](https://blog.joinmastodon.org/2022/
|
|||||||
[set as default](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted-as-default)
|
[set as default](https://github.com/sk22/mastodon-android-fork/tree/feature/enable-unlisted-as-default)
|
||||||
* [Add "Federation" tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline)
|
* [Add "Federation" tab and change Discover tab order](https://github.com/sk22/mastodon-android-fork/tree/feature/add-federated-timeline)
|
||||||
* [Add image description button and viewer](https://github.com/sk22/mastodon-android-fork/tree/feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
|
* [Add image description button and viewer](https://github.com/sk22/mastodon-android-fork/tree/feature/display-alt-text) ([Pull request](https://github.com/mastodon/mastodon-android/pull/129))
|
||||||
|
* [Implement pinning posts and displaying pinned posts](https://github.com/sk22/mastodon-android-fork/tree/feature/pin-posts) ([Pull request](https://github.com/mastodon/mastodon-android/pull/140))
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
@@ -23,4 +24,4 @@ As this app is using Java 17 features, you need JDK 17 or newer to build it. Oth
|
|||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is released under the [GPL-3 License](./LICENSE).
|
This project is released under the [GPL-3 License](./LICENSE).
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ android {
|
|||||||
applicationId "org.joinmastodon.android.sk"
|
applicationId "org.joinmastodon.android.sk"
|
||||||
minSdk 23
|
minSdk 23
|
||||||
targetSdk 31
|
targetSdk 31
|
||||||
versionCode 5
|
versionCode 8
|
||||||
versionName '1.1.1-dev+fork.1'
|
versionName '1.1.1-dev+fork.8'
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public class GetAccountStatuses extends MastodonAPIRequest<List<Status>>{
|
|||||||
switch(filter){
|
switch(filter){
|
||||||
case DEFAULT -> addQueryParameter("exclude_replies", "true");
|
case DEFAULT -> addQueryParameter("exclude_replies", "true");
|
||||||
case INCLUDE_REPLIES -> {}
|
case INCLUDE_REPLIES -> {}
|
||||||
|
case PINNED -> addQueryParameter("pinned", "true");
|
||||||
case MEDIA -> addQueryParameter("only_media", "true");
|
case MEDIA -> addQueryParameter("only_media", "true");
|
||||||
case NO_REBLOGS -> {
|
case NO_REBLOGS -> {
|
||||||
addQueryParameter("exclude_replies", "true");
|
addQueryParameter("exclude_replies", "true");
|
||||||
@@ -32,6 +33,7 @@ public class GetAccountStatuses extends MastodonAPIRequest<List<Status>>{
|
|||||||
public enum Filter{
|
public enum Filter{
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
INCLUDE_REPLIES,
|
INCLUDE_REPLIES,
|
||||||
|
PINNED,
|
||||||
MEDIA,
|
MEDIA,
|
||||||
NO_REBLOGS
|
NO_REBLOGS
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ public class CreateOAuthApp extends MastodonAPIRequest<Application>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static class Request{
|
private static class Request{
|
||||||
public String clientName="Mastodon for Android";
|
public String clientName="Mastodon for Android (Fork)";
|
||||||
public String redirectUris=AccountSessionManager.REDIRECT_URI;
|
public String redirectUris=AccountSessionManager.REDIRECT_URI;
|
||||||
public String scopes=AccountSessionManager.SCOPE;
|
public String scopes=AccountSessionManager.SCOPE;
|
||||||
public String website="https://app.joinmastodon.org/android";
|
public String website="https://github.com/sk22/mastodon-android-fork";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.joinmastodon.android.api.requests.statuses;
|
||||||
|
|
||||||
|
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||||
|
import org.joinmastodon.android.model.Status;
|
||||||
|
|
||||||
|
public class SetStatusPinned extends MastodonAPIRequest<Status>{
|
||||||
|
public SetStatusPinned(String id, boolean pinned){
|
||||||
|
super(HttpMethod.POST, "/statuses/"+id+"/"+(pinned ? "pin" : "unpin"), Status.class);
|
||||||
|
setRequestBody(new Object());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import org.joinmastodon.android.model.Status;
|
|||||||
public class StatusCountersUpdatedEvent{
|
public class StatusCountersUpdatedEvent{
|
||||||
public String id;
|
public String id;
|
||||||
public int favorites, reblogs, replies;
|
public int favorites, reblogs, replies;
|
||||||
public boolean favorited, reblogged;
|
public boolean favorited, reblogged, pinned;
|
||||||
|
|
||||||
public StatusCountersUpdatedEvent(Status s){
|
public StatusCountersUpdatedEvent(Status s){
|
||||||
id=s.id;
|
id=s.id;
|
||||||
@@ -14,5 +14,6 @@ public class StatusCountersUpdatedEvent{
|
|||||||
replies=s.repliesCount;
|
replies=s.repliesCount;
|
||||||
favorited=s.favourited;
|
favorited=s.favourited;
|
||||||
reblogged=s.reblogged;
|
reblogged=s.reblogged;
|
||||||
|
pinned=s.pinned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package org.joinmastodon.android.events;
|
||||||
|
|
||||||
|
public class StatusUnpinnedEvent {
|
||||||
|
public final String id;
|
||||||
|
public final String accountID;
|
||||||
|
|
||||||
|
public StatusUnpinnedEvent(String id, String accountID){
|
||||||
|
this.id=id;
|
||||||
|
this.accountID=accountID;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,8 +8,10 @@ import org.joinmastodon.android.R;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
|
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||||
import org.joinmastodon.android.model.Account;
|
import org.joinmastodon.android.model.Account;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
|
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||||
import org.parceler.Parcels;
|
import org.parceler.Parcels;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -76,6 +78,7 @@ public class AccountTimelineFragment extends StatusListFragment{
|
|||||||
protected void onStatusCreated(StatusCreatedEvent ev){
|
protected void onStatusCreated(StatusCreatedEvent ev){
|
||||||
if(!AccountSessionManager.getInstance().isSelf(accountID, ev.status.account))
|
if(!AccountSessionManager.getInstance().isSelf(accountID, ev.status.account))
|
||||||
return;
|
return;
|
||||||
|
if(filter==GetAccountStatuses.Filter.PINNED) return;
|
||||||
if(filter==GetAccountStatuses.Filter.DEFAULT){
|
if(filter==GetAccountStatuses.Filter.DEFAULT){
|
||||||
// Keep replies to self, discard all other replies
|
// Keep replies to self, discard all other replies
|
||||||
if(ev.status.inReplyToAccountId!=null && !ev.status.inReplyToAccountId.equals(AccountSessionManager.getInstance().getAccount(accountID).self.id))
|
if(ev.status.inReplyToAccountId!=null && !ev.status.inReplyToAccountId.equals(AccountSessionManager.getInstance().getAccount(accountID).self.id))
|
||||||
@@ -86,4 +89,24 @@ public class AccountTimelineFragment extends StatusListFragment{
|
|||||||
}
|
}
|
||||||
prependItems(Collections.singletonList(ev.status), true);
|
prependItems(Collections.singletonList(ev.status), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onStatusUnpinned(StatusUnpinnedEvent ev){
|
||||||
|
if(!ev.accountID.equals(accountID) || filter!=GetAccountStatuses.Filter.PINNED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Status status=getStatusByID(ev.id);
|
||||||
|
data.remove(status);
|
||||||
|
preloadedData.remove(status);
|
||||||
|
HeaderStatusDisplayItem item=findItemOfType(ev.id, HeaderStatusDisplayItem.class);
|
||||||
|
if(item==null)
|
||||||
|
return;
|
||||||
|
int index=displayItems.indexOf(item);
|
||||||
|
int lastIndex;
|
||||||
|
for(lastIndex=index;lastIndex<displayItems.size();lastIndex++){
|
||||||
|
if(!displayItems.get(lastIndex).parentID.equals(ev.id))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
displayItems.subList(index, lastIndex).clear();
|
||||||
|
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
private ProgressBarButton actionButton;
|
private ProgressBarButton actionButton;
|
||||||
private ViewPager2 pager;
|
private ViewPager2 pager;
|
||||||
private NestedRecyclerScrollView scrollView;
|
private NestedRecyclerScrollView scrollView;
|
||||||
private AccountTimelineFragment postsFragment, postsWithRepliesFragment, mediaFragment;
|
private AccountTimelineFragment postsFragment, postsWithRepliesFragment, pinnedPostsFragment, mediaFragment;
|
||||||
private ProfileAboutFragment aboutFragment;
|
private ProfileAboutFragment aboutFragment;
|
||||||
private TabLayout tabbar;
|
private TabLayout tabbar;
|
||||||
private SwipeRefreshLayout refreshLayout;
|
private SwipeRefreshLayout refreshLayout;
|
||||||
@@ -209,14 +209,15 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tabViews=new FrameLayout[4];
|
tabViews=new FrameLayout[5];
|
||||||
for(int i=0;i<tabViews.length;i++){
|
for(int i=0;i<tabViews.length;i++){
|
||||||
FrameLayout tabView=new FrameLayout(getActivity());
|
FrameLayout tabView=new FrameLayout(getActivity());
|
||||||
tabView.setId(switch(i){
|
tabView.setId(switch(i){
|
||||||
case 0 -> R.id.profile_posts;
|
case 0 -> R.id.profile_posts;
|
||||||
case 1 -> R.id.profile_posts_with_replies;
|
case 1 -> R.id.profile_posts_with_replies;
|
||||||
case 2 -> R.id.profile_media;
|
case 2 -> R.id.profile_pinned_posts;
|
||||||
case 3 -> R.id.profile_about;
|
case 3 -> R.id.profile_media;
|
||||||
|
case 4 -> R.id.profile_about;
|
||||||
default -> throw new IllegalStateException("Unexpected value: "+i);
|
default -> throw new IllegalStateException("Unexpected value: "+i);
|
||||||
});
|
});
|
||||||
tabView.setVisibility(View.GONE);
|
tabView.setVisibility(View.GONE);
|
||||||
@@ -224,7 +225,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
tabViews[i]=tabView;
|
tabViews[i]=tabView;
|
||||||
}
|
}
|
||||||
|
|
||||||
pager.setOffscreenPageLimit(4);
|
pager.setOffscreenPageLimit(5);
|
||||||
pager.setAdapter(new ProfilePagerAdapter());
|
pager.setAdapter(new ProfilePagerAdapter());
|
||||||
pager.getLayoutParams().height=getResources().getDisplayMetrics().heightPixels;
|
pager.getLayoutParams().height=getResources().getDisplayMetrics().heightPixels;
|
||||||
|
|
||||||
@@ -240,8 +241,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
tab.setText(switch(position){
|
tab.setText(switch(position){
|
||||||
case 0 -> R.string.posts;
|
case 0 -> R.string.posts;
|
||||||
case 1 -> R.string.posts_and_replies;
|
case 1 -> R.string.posts_and_replies;
|
||||||
case 2 -> R.string.media;
|
case 2 -> R.string.pinned_posts;
|
||||||
case 3 -> R.string.profile_about;
|
case 3 -> R.string.media;
|
||||||
|
case 4 -> R.string.profile_about;
|
||||||
default -> throw new IllegalStateException();
|
default -> throw new IllegalStateException();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -298,6 +300,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
postsFragment.onRefresh();
|
postsFragment.onRefresh();
|
||||||
if(postsWithRepliesFragment.loaded)
|
if(postsWithRepliesFragment.loaded)
|
||||||
postsWithRepliesFragment.onRefresh();
|
postsWithRepliesFragment.onRefresh();
|
||||||
|
if(pinnedPostsFragment.loaded)
|
||||||
|
pinnedPostsFragment.onRefresh();
|
||||||
if(mediaFragment.loaded)
|
if(mediaFragment.loaded)
|
||||||
mediaFragment.onRefresh();
|
mediaFragment.onRefresh();
|
||||||
}
|
}
|
||||||
@@ -322,6 +326,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
if(postsFragment==null){
|
if(postsFragment==null){
|
||||||
postsFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.DEFAULT, true);
|
postsFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.DEFAULT, true);
|
||||||
postsWithRepliesFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.INCLUDE_REPLIES, false);
|
postsWithRepliesFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.INCLUDE_REPLIES, false);
|
||||||
|
pinnedPostsFragment =AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.PINNED, false);
|
||||||
mediaFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.MEDIA, false);
|
mediaFragment=AccountTimelineFragment.newInstance(accountID, account, GetAccountStatuses.Filter.MEDIA, false);
|
||||||
aboutFragment=new ProfileAboutFragment();
|
aboutFragment=new ProfileAboutFragment();
|
||||||
aboutFragment.setFields(fields);
|
aboutFragment.setFields(fields);
|
||||||
@@ -402,6 +407,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
if(postsFragment!=null && postsFragment.isAdded() && childInsets!=null){
|
if(postsFragment!=null && postsFragment.isAdded() && childInsets!=null){
|
||||||
postsFragment.onApplyWindowInsets(childInsets);
|
postsFragment.onApplyWindowInsets(childInsets);
|
||||||
postsWithRepliesFragment.onApplyWindowInsets(childInsets);
|
postsWithRepliesFragment.onApplyWindowInsets(childInsets);
|
||||||
|
pinnedPostsFragment.onApplyWindowInsets(childInsets);
|
||||||
mediaFragment.onApplyWindowInsets(childInsets);
|
mediaFragment.onApplyWindowInsets(childInsets);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,8 +643,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
return switch(page){
|
return switch(page){
|
||||||
case 0 -> postsFragment;
|
case 0 -> postsFragment;
|
||||||
case 1 -> postsWithRepliesFragment;
|
case 1 -> postsWithRepliesFragment;
|
||||||
case 2 -> mediaFragment;
|
case 2 -> pinnedPostsFragment;
|
||||||
case 3 -> aboutFragment;
|
case 3 -> mediaFragment;
|
||||||
|
case 4 -> aboutFragment;
|
||||||
default -> throw new IllegalStateException();
|
default -> throw new IllegalStateException();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -699,9 +706,9 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
pager.setUserInputEnabled(false);
|
pager.setUserInputEnabled(false);
|
||||||
actionButton.setText(R.string.done);
|
actionButton.setText(R.string.done);
|
||||||
pager.setCurrentItem(3);
|
pager.setCurrentItem(4);
|
||||||
ArrayList<Animator> animators=new ArrayList<>();
|
ArrayList<Animator> animators=new ArrayList<>();
|
||||||
for(int i=0;i<3;i++){
|
for(int i=0;i<tabViews.length-1;i++){
|
||||||
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, .3f));
|
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, .3f));
|
||||||
tabbar.getTabAt(i).view.setEnabled(false);
|
tabbar.getTabAt(i).view.setEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -742,7 +749,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
invalidateOptionsMenu();
|
invalidateOptionsMenu();
|
||||||
ArrayList<Animator> animators=new ArrayList<>();
|
ArrayList<Animator> animators=new ArrayList<>();
|
||||||
actionButton.setText(R.string.edit_profile);
|
actionButton.setText(R.string.edit_profile);
|
||||||
for(int i=0;i<3;i++){
|
for(int i=0;i<tabViews.length-1;i++){
|
||||||
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, 1f));
|
animators.add(ObjectAnimator.ofFloat(tabbar.getTabAt(i).view, View.ALPHA, 1f));
|
||||||
}
|
}
|
||||||
animators.add(ObjectAnimator.ofInt(avatar.getForeground(), "alpha", 0));
|
animators.add(ObjectAnimator.ofInt(avatar.getForeground(), "alpha", 0));
|
||||||
@@ -760,7 +767,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
set.addListener(new AnimatorListenerAdapter(){
|
set.addListener(new AnimatorListenerAdapter(){
|
||||||
@Override
|
@Override
|
||||||
public void onAnimationEnd(Animator animation){
|
public void onAnimationEnd(Animator animation){
|
||||||
for(int i=0;i<3;i++){
|
for(int i=0;i<tabViews.length-1;i++){
|
||||||
tabbar.getTabAt(i).view.setEnabled(true);
|
tabbar.getTabAt(i).view.setEnabled(true);
|
||||||
}
|
}
|
||||||
pager.setUserInputEnabled(true);
|
pager.setUserInputEnabled(true);
|
||||||
@@ -937,7 +944,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount(){
|
public int getItemCount(){
|
||||||
return loaded ? 4 : 0;
|
return loaded ? tabViews.length : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.joinmastodon.android.events.PollUpdatedEvent;
|
|||||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||||
|
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||||
import org.joinmastodon.android.model.Status;
|
import org.joinmastodon.android.model.Status;
|
||||||
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
|
||||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||||
@@ -61,6 +62,8 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
|
|
||||||
protected void onStatusCreated(StatusCreatedEvent ev){}
|
protected void onStatusCreated(StatusCreatedEvent ev){}
|
||||||
|
|
||||||
|
protected void onStatusUnpinned(StatusUnpinnedEvent ev){}
|
||||||
|
|
||||||
protected Status getContentStatusByID(String id){
|
protected Status getContentStatusByID(String id){
|
||||||
Status s=getStatusByID(id);
|
Status s=getStatusByID(id);
|
||||||
return s==null ? null : s.getContentStatus();
|
return s==null ? null : s.getContentStatus();
|
||||||
@@ -131,6 +134,11 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
|||||||
StatusListFragment.this.onStatusCreated(ev);
|
StatusListFragment.this.onStatusCreated(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onStatusUnpinned(StatusUnpinnedEvent ev){
|
||||||
|
StatusListFragment.this.onStatusUnpinned(ev);
|
||||||
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onPollUpdated(PollUpdatedEvent ev){
|
public void onPollUpdated(PollUpdatedEvent ev){
|
||||||
if(!ev.accountID.equals(accountID))
|
if(!ev.accountID.equals(accountID))
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
|||||||
repliesCount=ev.replies;
|
repliesCount=ev.replies;
|
||||||
favourited=ev.favorited;
|
favourited=ev.favorited;
|
||||||
reblogged=ev.reblogged;
|
reblogged=ev.reblogged;
|
||||||
|
pinned=ev.pinned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Status getContentStatus(){
|
public Status getContentStatus(){
|
||||||
|
|||||||
@@ -137,6 +137,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
int id=menuItem.getItemId();
|
int id=menuItem.getItemId();
|
||||||
if(id==R.id.delete){
|
if(id==R.id.delete){
|
||||||
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{});
|
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{});
|
||||||
|
}else if(id==R.id.pin || id==R.id.unpin){
|
||||||
|
UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{});
|
||||||
}else if(id==R.id.mute){
|
}else if(id==R.id.mute){
|
||||||
UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.muting, r->{});
|
UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.muting, r->{});
|
||||||
}else if(id==R.id.block){
|
}else if(id==R.id.block){
|
||||||
@@ -250,6 +252,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
|||||||
Menu menu=optionsMenu.getMenu();
|
Menu menu=optionsMenu.getMenu();
|
||||||
boolean isOwnPost=AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account);
|
boolean isOwnPost=AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account);
|
||||||
menu.findItem(R.id.delete).setVisible(item.status!=null && isOwnPost);
|
menu.findItem(R.id.delete).setVisible(item.status!=null && isOwnPost);
|
||||||
|
menu.findItem(R.id.pin).setVisible(item.status!=null && isOwnPost && !item.status.pinned);
|
||||||
|
menu.findItem(R.id.unpin).setVisible(item.status!=null && isOwnPost && item.status.pinned);
|
||||||
menu.findItem(R.id.open_in_browser).setVisible(item.status!=null);
|
menu.findItem(R.id.open_in_browser).setVisible(item.status!=null);
|
||||||
MenuItem blockDomain=menu.findItem(R.id.block_domain);
|
MenuItem blockDomain=menu.findItem(R.id.block_domain);
|
||||||
MenuItem mute=menu.findItem(R.id.mute);
|
MenuItem mute=menu.findItem(R.id.mute);
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import android.view.WindowManager;
|
|||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.PopupWindow;
|
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
import android.widget.SeekBar;
|
import android.widget.SeekBar;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -57,7 +56,6 @@ import java.io.File;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@@ -73,7 +71,6 @@ import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
|||||||
import me.grishka.appkit.utils.BindableViewHolder;
|
import me.grishka.appkit.utils.BindableViewHolder;
|
||||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||||
import me.grishka.appkit.utils.V;
|
import me.grishka.appkit.utils.V;
|
||||||
import me.grishka.appkit.views.BottomSheet;
|
|
||||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||||
import okio.BufferedSink;
|
import okio.BufferedSink;
|
||||||
import okio.Okio;
|
import okio.Okio;
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import android.content.res.TypedArray;
|
|||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Typeface;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.InsetDrawable;
|
import android.graphics.drawable.InsetDrawable;
|
||||||
@@ -42,8 +41,11 @@ import org.joinmastodon.android.api.requests.accounts.SetAccountMuted;
|
|||||||
import org.joinmastodon.android.api.requests.accounts.SetDomainBlocked;
|
import org.joinmastodon.android.api.requests.accounts.SetDomainBlocked;
|
||||||
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
|
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
|
||||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
||||||
|
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
|
||||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||||
|
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||||
|
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||||
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
|
||||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||||
import org.joinmastodon.android.fragments.ThreadFragment;
|
import org.joinmastodon.android.fragments.ThreadFragment;
|
||||||
@@ -349,6 +351,32 @@ public class UiUtils{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void confirmPinPost(Activity activity, String accountID, Status status, boolean pinned, Consumer<Status> resultCallback){
|
||||||
|
showConfirmationAlert(activity,
|
||||||
|
pinned ? R.string.confirm_pin_post_title : R.string.confirm_unpin_post_title,
|
||||||
|
pinned ? R.string.confirm_pin_post : R.string.confirm_unpin_post,
|
||||||
|
pinned ? R.string.pin_post : R.string.unpin_post,
|
||||||
|
()->{
|
||||||
|
new SetStatusPinned(status.id, pinned)
|
||||||
|
.setCallback(new Callback<>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Status result) {
|
||||||
|
resultCallback.accept(result);
|
||||||
|
E.post(new StatusCountersUpdatedEvent(result));
|
||||||
|
if (!result.pinned)
|
||||||
|
E.post(new StatusUnpinnedEvent(status.id, accountID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(ErrorResponse error) {
|
||||||
|
error.showToast(activity);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.wrapProgress(activity, pinned ? R.string.pinning : R.string.unpinning, false)
|
||||||
|
.exec(accountID);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static void setRelationshipToActionButton(Relationship relationship, Button button){
|
public static void setRelationshipToActionButton(Relationship relationship, Button button){
|
||||||
boolean secondaryStyle;
|
boolean secondaryStyle;
|
||||||
if(relationship.blocking){
|
if(relationship.blocking){
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<?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/delete" android:title="@string/delete"/>
|
<item android:id="@+id/delete" android:title="@string/delete"/>
|
||||||
|
<item android:id="@+id/pin" android:title="@string/pin_post"/>
|
||||||
|
<item android:id="@+id/unpin" android:title="@string/unpin_post"/>
|
||||||
<item android:id="@+id/mute" android:title="@string/mute_user"/>
|
<item android:id="@+id/mute" android:title="@string/mute_user"/>
|
||||||
<item android:id="@+id/block" android:title="@string/block_user"/>
|
<item android:id="@+id/block" android:title="@string/block_user"/>
|
||||||
<item android:id="@+id/block_domain" android:title="@string/block_domain"/>
|
<item android:id="@+id/block_domain" android:title="@string/block_domain"/>
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="posts">Beiträge</string>
|
<string name="posts">Beiträge</string>
|
||||||
<string name="posts_and_replies">Beiträge und Antworten</string>
|
<string name="posts_and_replies">Beiträge und Antworten</string>
|
||||||
|
<string name="pinned_posts">Angeheftet</string>
|
||||||
<string name="media">Medien</string>
|
<string name="media">Medien</string>
|
||||||
<string name="profile_about">Über</string>
|
<string name="profile_about">Über</string>
|
||||||
<string name="button_follow">Folgen</string>
|
<string name="button_follow">Folgen</string>
|
||||||
@@ -124,6 +125,14 @@
|
|||||||
<string name="confirm_delete_title">Beitrag löschen</string>
|
<string name="confirm_delete_title">Beitrag löschen</string>
|
||||||
<string name="confirm_delete">Bist du dir sicher, dass du den Beitrag löschen möchtest?</string>
|
<string name="confirm_delete">Bist du dir sicher, dass du den Beitrag löschen möchtest?</string>
|
||||||
<string name="deleting">Wird gelöscht…</string>
|
<string name="deleting">Wird gelöscht…</string>
|
||||||
|
<string name="pin_post">An Profil anheften</string>
|
||||||
|
<string name="confirm_pin_post_title">Beitrag an Profil anheften</string>
|
||||||
|
<string name="confirm_pin_post">Möchtest du den Beitrag an dein Profil anheften?</string>
|
||||||
|
<string name="pinning">Wird angeheftet…</string>
|
||||||
|
<string name="unpin_post">Von Profil lösen</string>
|
||||||
|
<string name="confirm_unpin_post_title">Angehefteten Beitrag von Profil lösen</string>
|
||||||
|
<string name="confirm_unpin_post">Bist du dir sicher, dass du den angehefteten Beitrag von deinem Profil lösen möchtest?</string>
|
||||||
|
<string name="unpinning">Wird vom Profil gelöst…</string>
|
||||||
<string name="notification_channel_audio_player">Audiowiedergabe</string>
|
<string name="notification_channel_audio_player">Audiowiedergabe</string>
|
||||||
<string name="play">Abspielen</string>
|
<string name="play">Abspielen</string>
|
||||||
<string name="pause">Pausieren</string>
|
<string name="pause">Pausieren</string>
|
||||||
@@ -317,7 +326,7 @@
|
|||||||
<string name="manually_approves_followers">Genehmigt Folgende manuell</string>
|
<string name="manually_approves_followers">Genehmigt Folgende manuell</string>
|
||||||
<string name="current_account">Aktuelles Konto</string>
|
<string name="current_account">Aktuelles Konto</string>
|
||||||
<string name="log_out_account">%s ausloggen</string>
|
<string name="log_out_account">%s ausloggen</string>
|
||||||
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
|
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
|
||||||
<plurals name="x_followers">
|
<plurals name="x_followers">
|
||||||
<item quantity="one">%,d Follower</item>
|
<item quantity="one">%,d Follower</item>
|
||||||
<item quantity="other">%,d Follower</item>
|
<item quantity="other">%,d Follower</item>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
<item name="profile_posts" type="id"/>
|
<item name="profile_posts" type="id"/>
|
||||||
<item name="profile_posts_with_replies" type="id"/>
|
<item name="profile_posts_with_replies" type="id"/>
|
||||||
|
<item name="profile_pinned_posts" type="id"/>
|
||||||
<item name="profile_media" type="id"/>
|
<item name="profile_media" type="id"/>
|
||||||
<item name="profile_about" type="id"/>
|
<item name="profile_about" type="id"/>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Mastodon</string>
|
<string name="app_name">Mastođon</string>
|
||||||
|
|
||||||
<string name="get_started">Get started</string>
|
<string name="get_started">Get started</string>
|
||||||
<string name="log_in">Log in</string>
|
<string name="log_in">Log in</string>
|
||||||
@@ -47,6 +47,7 @@
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="posts">Posts</string>
|
<string name="posts">Posts</string>
|
||||||
<string name="posts_and_replies">Posts and Replies</string>
|
<string name="posts_and_replies">Posts and Replies</string>
|
||||||
|
<string name="pinned_posts">Pinned</string>
|
||||||
<string name="media">Media</string>
|
<string name="media">Media</string>
|
||||||
<string name="profile_about">About</string>
|
<string name="profile_about">About</string>
|
||||||
<string name="button_follow">Follow</string>
|
<string name="button_follow">Follow</string>
|
||||||
@@ -129,6 +130,14 @@
|
|||||||
<string name="confirm_delete_title">Delete Post</string>
|
<string name="confirm_delete_title">Delete Post</string>
|
||||||
<string name="confirm_delete">Are you sure you want to delete this post?</string>
|
<string name="confirm_delete">Are you sure you want to delete this post?</string>
|
||||||
<string name="deleting">Deleting…</string>
|
<string name="deleting">Deleting…</string>
|
||||||
|
<string name="pin_post">Pin to profile</string>
|
||||||
|
<string name="confirm_pin_post_title">Pin post to profile</string>
|
||||||
|
<string name="confirm_pin_post">Do you want to pin this post to your profile?</string>
|
||||||
|
<string name="pinning">Pinning post…</string>
|
||||||
|
<string name="unpin_post">Unpin from profile</string>
|
||||||
|
<string name="confirm_unpin_post_title">Unpin post from profile</string>
|
||||||
|
<string name="confirm_unpin_post">Are you sure you want to unpin this post?</string>
|
||||||
|
<string name="unpinning">Unpinning post…</string>
|
||||||
<string name="notification_channel_audio_player">Audio playback</string>
|
<string name="notification_channel_audio_player">Audio playback</string>
|
||||||
<string name="play">Play</string>
|
<string name="play">Play</string>
|
||||||
<string name="pause">Pause</string>
|
<string name="pause">Pause</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user