Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iceshrimp improvements #516

Open
wants to merge 32 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
53e8c0d
Quoting
Jacocococo Feb 14, 2024
c8bb0de
Don't load instance info in background
Jacocococo Feb 14, 2024
2892a31
Hide news discovery on Iceshrimp
Jacocococo Feb 14, 2024
0e96e23
Hide language selector on Iceshrimp
Jacocococo Feb 14, 2024
325eda5
Fix Iceshrimp quote notification
Jacocococo Feb 15, 2024
454660f
Hide profile notify button on Iceshrimp
Jacocococo Feb 15, 2024
3593d8d
Announcements fixes on Iceshrimp
Jacocococo Feb 15, 2024
86f54f5
Respect instance max reaction count
Jacocococo Mar 15, 2024
2dfb79c
Disable remote emoji reaction buttons on Iceshrimp
Jacocococo Mar 16, 2024
6841649
Disable add reaction button upon reaching limit when using that button
Jacocococo Mar 16, 2024
2856e99
Update favorite when reacting on Iceshrimp
Jacocococo Mar 16, 2024
86b6adf
Move unauthenticatedApiController
Jacocococo Mar 29, 2024
3266a49
Add reaction when favoriting post on Iceshrimp
Jacocococo Aug 5, 2024
1ad2257
Add favorite reaction in right place + fix issues
Jacocococo Aug 19, 2024
5f78cd4
Fix unicode reaction not showing up if no reactions were previsouly p…
Jacocococo Aug 19, 2024
309d272
Fix crash when liking statuses from non-Iceshrimp instances
Jacocococo Aug 19, 2024
5d411e8
Place new reaction where server specified it
Jacocococo Aug 19, 2024
6a46815
Prevent more reactions if max has been reached
Jacocococo Aug 19, 2024
cd7c546
Only allow MFM content type on Iceshrimp
Jacocococo Aug 19, 2024
96b9920
Disable content type setting on Iceshrimp
Jacocococo Aug 19, 2024
893b883
Allow all content types on Iceshrimp
Jacocococo Aug 19, 2024
c834199
Hide filter settings on Iceshrimp
Jacocococo Aug 19, 2024
4078443
Revert some changes specifically for Iceshrimp.NET
Jacocococo Aug 21, 2024
fcf7665
Merge branch 'master' of https://github.com/LucasGGamerM/moshidon int…
Jacocococo Aug 22, 2024
e3df5ce
Properly set emoji reactions padding
Jacocococo Aug 22, 2024
87cbffc
Better code style for hiding language button
Jacocococo Aug 27, 2024
f28e06d
Code comments about hiding news discovery on Iceshrimp
Jacocococo Aug 27, 2024
f146067
Code comments to clear up isIceshrimp and isIceshrimpJs
Jacocococo Aug 27, 2024
9426a9b
Code comments clarifying features being hidden on some servers
Jacocococo Aug 27, 2024
f016b87
Fix indent
Jacocococo Aug 28, 2024
a554059
Change isAkkoma to be based on version code
Jacocococo Sep 14, 2024
e336f15
Don't hide filter settings on Iceshrimp.NET
Jacocococo Sep 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
private static final String TAG="MastodonAPIRequest";

private static MastodonAPIController unauthenticatedApiController=new MastodonAPIController(null);

private String domain;
private AccountSession account;
private String path;
Expand Down Expand Up @@ -95,14 +97,14 @@ public MastodonAPIRequest<T> exec(String accountID){

public MastodonAPIRequest<T> execNoAuth(String domain){
this.domain=domain;
AccountSessionManager.getInstance().getUnauthenticatedApiController().submitRequest(this);
unauthenticatedApiController.submitRequest(this);
return this;
}

public MastodonAPIRequest<T> exec(String domain, Token token){
this.domain=domain;
this.token=token;
AccountSessionManager.getInstance().getUnauthenticatedApiController().submitRequest(this);
unauthenticatedApiController.submitRequest(this);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,23 @@
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusMuted;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.ReblogDeletedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusDeletedEvent;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.EmojiReaction;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;

import me.grishka.appkit.api.Callback;
Expand All @@ -42,6 +51,9 @@ public void setFavorited(Status status, boolean favorited, Consumer<Status> cb){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");

AccountSession session=AccountSessionManager.get(accountID);
Instance instance=session.getInstance().get();

SetStatusFavorited current=runningFavoriteRequests.remove(status.id);
if(current!=null){
current.cancel();
Expand All @@ -54,6 +66,7 @@ public void onSuccess(Status result){
result.favouritesCount = Math.max(0, status.favouritesCount + (favorited ? 1 : -1));
cb.accept(result);
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
if(instance.isIceshrimpJs()) E.post(new EmojiReactionsUpdatedEvent(status.id, result.reactions, false, null));
}

@Override
Expand All @@ -63,12 +76,58 @@ public void onError(ErrorResponse error){
status.favourited=!favorited;
cb.accept(status);
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
if(instance.isIceshrimpJs()) E.post(new EmojiReactionsUpdatedEvent(status.id, status.reactions, false, null));
}
})
.exec(accountID);
runningFavoriteRequests.put(status.id, req);
status.favourited=favorited;
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));

if(instance.configuration==null || instance.configuration.reactions==null)
return;

String defaultReactionEmojiRaw=instance.configuration.reactions.defaultReaction;
if(!instance.isIceshrimpJs() || defaultReactionEmojiRaw==null)
return;

boolean reactionIsCustom=defaultReactionEmojiRaw.startsWith(":");
String defaultReactionEmoji=reactionIsCustom ? defaultReactionEmojiRaw.substring(1, defaultReactionEmojiRaw.length()-1) : defaultReactionEmojiRaw;
ArrayList<EmojiReaction> reactions=new ArrayList<>(status.reactions.size());
for(EmojiReaction reaction:status.reactions){
reactions.add(reaction.copy());
}
Optional<EmojiReaction> existingReaction=reactions.stream().filter(r->r.me).findFirst();
Optional<EmojiReaction> existingDefaultReaction=reactions.stream().filter(r->r.name.equals(defaultReactionEmoji)).findFirst();
if(existingReaction.isPresent() && !favorited){
existingReaction.get().me=false;
existingReaction.get().count--;
existingReaction.get().pendingChange=true;
}else if(existingDefaultReaction.isPresent() && favorited){
existingDefaultReaction.get().count++;
existingDefaultReaction.get().me=true;
existingDefaultReaction.get().pendingChange=true;
}else if(favorited){
EmojiReaction reaction=null;
if(reactionIsCustom){
List<EmojiCategory> customEmojis=AccountSessionManager.getInstance().getCustomEmojis(session.domain);
for(EmojiCategory category:customEmojis){
for(Emoji emoji:category.emojis){
if(emoji.shortcode.equals(defaultReactionEmoji)){
reaction=EmojiReaction.of(emoji, session.self);
break;
}
}
}
if(reaction==null)
reaction=EmojiReaction.of(defaultReactionEmoji, session.self);
}else{
reaction=EmojiReaction.of(defaultReactionEmoji, session.self);
}
reaction.pendingChange=true;
reactions.add(reaction);
}
E.post(new EmojiReactionsUpdatedEvent(status.id, reactions, false, null));
}

public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.PushSubscription;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.TimelineDefinition;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class AccountLocalPreferences{
private final SharedPreferences prefs;
Expand Down Expand Up @@ -72,19 +74,20 @@ public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
// preReplySheet=prefs.getBoolean("preReplySheet", false);

// MEGALODON
Optional<Instance> instance=session.getInstance();
showReplies=prefs.getBoolean("showReplies", true);
showBoosts=prefs.getBoolean("showBoosts", true);
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new ArrayList<>());
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
defaultContentType=enumValue(ContentType.class, prefs.getString("defaultContentType", ContentType.PLAIN.name()));
contentTypesEnabled=prefs.getBoolean("contentTypesEnabled", true);
defaultContentType=enumValue(ContentType.class, prefs.getString("defaultContentType", instance.map(Instance::isIceshrimp).orElse(false) ? ContentType.MISSKEY_MARKDOWN.name() : ContentType.PLAIN.name()));
contentTypesEnabled=prefs.getBoolean("contentTypesEnabled", instance.map(i->!i.isIceshrimp()).orElse(false));
timelines=fromJson(prefs.getString("timelines", null), timelinesType, TimelineDefinition.getDefaultTimelines(session.getID()));
localOnlySupported=prefs.getBoolean("localOnlySupported", false);
glitchInstance=prefs.getBoolean("glitchInstance", false);
publishButtonText=prefs.getString("publishButtonText", null);
timelineReplyVisibility=prefs.getString("timelineReplyVisibility", null);
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", instance.map(i->i.isAkkoma() || i.isIceshrimp()).orElse(false));
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
color=prefs.contains("color") ? ColorPreference.valueOf(prefs.getString("color", null)) : null;
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ public class AccountSessionManager{
private HashMap<String, List<EmojiCategory>> customEmojis=new HashMap<>();
private HashMap<String, Long> instancesLastUpdated=new HashMap<>();
private HashMap<String, Instance> instances=new HashMap<>();
private MastodonAPIController unauthenticatedApiController=new MastodonAPIController(null);
private Instance authenticatingInstance;
private Application authenticatingApp;
private String lastActiveAccountID;
Expand Down Expand Up @@ -109,7 +108,7 @@ private AccountSessionManager(){
Log.e(TAG, "Error loading accounts", x);
}
lastActiveAccountID=prefs.getString("lastActiveAccount", null);
MastodonAPIController.runInBackground(()->readInstanceInfo(domains));
readInstanceInfo(domains);
maybeUpdateShortcuts();
}

Expand Down Expand Up @@ -247,11 +246,6 @@ public void removeAccount(String id){
maybeUpdateShortcuts();
}

@NonNull
public MastodonAPIController getUnauthenticatedApiController(){
return unauthenticatedApiController;
}

public void authenticate(Activity activity, Instance instance){
authenticatingInstance=instance;
new CreateOAuthApp()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ protected List<StatusDisplayItem> buildDisplayItems(Announcement a) {
instanceUser.url = "https://"+session.domain+"/about";
instanceUser.avatar = instanceUser.avatarStatic = instance.thumbnail;
instanceUser.emojis = List.of();
Status fakeStatus = a.toStatus();
Status fakeStatus = a.toStatus(isInstanceIceshrimp());
TextStatusDisplayItem textItem = new TextStatusDisplayItem(a.id, HtmlParser.parse(a.content, a.emojis, a.mentions, a.tags, accountID), this, fakeStatus, true);
textItem.textSelectable = true;

List<StatusDisplayItem> items=new ArrayList<>();
items.add(HeaderStatusDisplayItem.fromAnnouncement(a, fakeStatus, instanceUser, this, accountID, this::onMarkAsRead));
items.add(textItem);
if(!isInstanceAkkoma()) items.add(new EmojiReactionsStatusDisplayItem(a.id, this, fakeStatus, accountID, false, true));
if(!isInstanceAkkoma() && !isInstanceIceshrimp()) items.add(new EmojiReactionsStatusDisplayItem(a.id, this, fakeStatus, accountID, false, true));
return items;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,14 @@ public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){
list.invalidateItemDecorations();
}

public void onFavoriteChanged(Status status, String itemID) {
FooterStatusDisplayItem.Holder footer=findHolderOfType(itemID, FooterStatusDisplayItem.Holder.class);
if(footer!=null){
footer.getItem().status=status;
footer.onFavoriteClick();
}
}

@Override
public String getAccountID(){
return accountID;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,9 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater){
}
return false;
});
if(instance.isIceshrimpJs())
languageButton.setVisibility(View.GONE); // hide language selector on Iceshrimp-JS because the feature is not supported

if (!GlobalUserPreferences.relocatePublishButton)
publishButton.post(()->publishButton.setMinimumWidth(publishButton.getWidth()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ default boolean isInstancePixelfed() {
return getInstance().map(Instance::isPixelfed).orElse(false);
}

default boolean isInstanceIceshrimp() {
return getInstance().map(Instance::isIceshrimp).orElse(false);
}

default boolean isInstanceIceshrimpJs() {
return getInstance().map(Instance::isIceshrimpJs).orElse(false);
}

default Optional<Instance> getInstance() {
return getSession().getInstance();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.Status;
Expand Down Expand Up @@ -122,7 +123,9 @@ protected List<StatusDisplayItem> buildDisplayItems(Notification n){
}

NotificationHeaderStatusDisplayItem titleItem;
if(n.type==Notification.Type.MENTION || n.type==Notification.Type.STATUS){
Account self=AccountSessionManager.get(accountID).self;
if(n.type==Notification.Type.MENTION || n.type==Notification.Type.STATUS
|| (n.type==Notification.Type.REBLOG && !n.status.account.id.equals(self.id))){ // Iceshrimp quote
titleItem=null;
}else{
titleItem=new NotificationHeaderStatusDisplayItem(n.id, this, n, accountID);
Expand Down Expand Up @@ -316,13 +319,16 @@ public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
for(Notification n : data){
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
n.status.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
for(int i=0; i<list.getChildCount(); i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==n.status.getContentStatus() && ev.viewHolder!=holder){
reactions.rebind();
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(n.getID())){
reactions.updateReactions(ev.reactions);
}
}
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(n.getID())){
text.rebind();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,7 @@ private void updateRelationship(){
else hidePrivateNote();
invalidateOptionsMenu();
actionButton.setVisibility(View.VISIBLE);
notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE);
notifyButton.setVisibility(relationship.following && !isInstanceIceshrimpJs() ? View.VISIBLE : View.GONE); // always hide notify button on Iceshrimp-JS because it's unsupported on the server
UiUtils.setRelationshipToActionButtonM3(relationship, actionButton);
actionProgress.setIndeterminateTintList(actionButton.getTextColors());
notifyProgress.setIndeterminateTintList(notifyButton.getTextColors());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,13 +327,16 @@ public void onStatusMuteChaged(StatusMuteChangedEvent ev){
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
for(Status s:data){
if(s.getContentStatus().id.equals(ev.id)){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==s.getContentStatus() && ev.viewHolder!=holder){
reactions.rebind();
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(s.getID())){
reactions.updateReactions(ev.reactions);
}
}
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(s.getID())){
text.rebind();
}
}
Expand Down
Loading