Compare commits

..

15 Commits

Author SHA1 Message Date
sk
244c5dc6b4 bump version 2023-03-24 19:58:10 +01:00
sk
cceb0b4c6c Merge remote-tracking branch 'upstream/master' 2023-03-24 19:33:40 +01:00
sk
a58640a718 fix crash when instance not yet loaded
closes sk22#474
2023-03-24 19:04:13 +01:00
Grishka
d6e563486b Fix alt text button 2023-03-22 02:46:48 +03:00
Grishka
0112bfa9c4 Fix #547 2023-03-22 02:38:58 +03:00
Grishka
5951611fb0 Fix #551 2023-03-22 02:34:25 +03:00
sk
2d31b726ac Merge branch 'main' of github.com:sk22/megalodon 2023-03-21 16:04:43 +01:00
sk22
d2f295ef88 Update README.md 2023-03-21 16:03:35 +01:00
sk
d1b53554ce bump version 2023-03-21 15:59:40 +01:00
sk
ec5db122d0 full text can have emojis, too 2023-03-21 15:56:44 +01:00
sk
0216e22fcc don't remove badge if loaded from cache 2023-03-21 15:25:01 +01:00
sk
5734b19d8c remove unused variable 2023-03-21 15:14:25 +01:00
sk
e58aeec097 query notifications on load posts
closes sk22#471
2023-03-21 10:22:09 +01:00
sk
58b000927a session-specific notification badge
fix sk22#470
2023-03-21 10:03:31 +01:00
sk
797642b972 fix profile fragment crash
closes sk22#469
2023-03-21 09:56:44 +01:00
16 changed files with 60 additions and 28 deletions

View File

@@ -55,7 +55,7 @@ On the Fediverse, its quite common for people to pin posts they want others t
[apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk) [apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk)
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a> <a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
Note that you'll need to add Izzy's F-Droid repository to your F-Droid app first: Note that you'll need to add Izzy's F-Droid repository to your F-Droid app first:

View File

@@ -9,8 +9,8 @@ android {
applicationId "org.joinmastodon.android.sk" applicationId "org.joinmastodon.android.sk"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 80 versionCode 82
versionName "1.2.0+fork.80" versionName "1.2.0+fork.82"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW" resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
} }

View File

@@ -17,6 +17,9 @@
<action android:name="android.intent.action.PROCESS_TEXT" /> <action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" /> <data android:mimeType="text/plain" />
</intent> </intent>
<intent>
<action android:name="android.intent.action.TRANSLATE" />
</intent>
</queries> </queries>
<application <application

View File

@@ -86,7 +86,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
} }
String accountID=account.getID(); String accountID=account.getID();
PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s); PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s);
E.post(new NotificationReceivedEvent(pn.notificationId+"")); E.post(new NotificationReceivedEvent(accountID, pn.notificationId+""));
new GetNotificationByID(pn.notificationId+"") new GetNotificationByID(pn.notificationId+"")
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override

View File

@@ -128,7 +128,7 @@ public class CacheController{
}); });
} }
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<PaginatedResponse<List<Notification>>> callback){ public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<CacheablePaginatedResponse<List<Notification>>> callback){
cancelDelayedClose(); cancelDelayedClose();
databaseThread.postRunnable(()->{ databaseThread.postRunnable(()->{
try{ try{
@@ -156,7 +156,7 @@ public class CacheController{
result.add(ntf); result.add(ntf);
}while(cursor.moveToNext()); }while(cursor.moveToNext());
String _newMaxID=newMaxID; String _newMaxID=newMaxID;
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(result, _newMaxID))); uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
return; return;
} }
}catch(IOException x){ }catch(IOException x){
@@ -168,7 +168,7 @@ public class CacheController{
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(List<Notification> result){ public void onSuccess(List<Notification> result){
callback.onSuccess(new PaginatedResponse<>(result.stream().filter(ntf->{ callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(ntf->{
if(ntf.status!=null){ if(ntf.status!=null){
for(Filter filter:filters){ for(Filter filter:filters){
if(filter.matches(ntf.status)){ if(filter.matches(ntf.status)){
@@ -177,7 +177,7 @@ public class CacheController{
} }
} }
return true; return true;
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id)); }).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
putNotifications(result, onlyMentions, onlyPosts, maxID==null); putNotifications(result, onlyMentions, onlyPosts, maxID==null);
} }

View File

@@ -1,8 +1,9 @@
package org.joinmastodon.android.events; package org.joinmastodon.android.events;
public class NotificationReceivedEvent { public class NotificationReceivedEvent {
public String id; public String account, id;
public NotificationReceivedEvent(String id) { public NotificationReceivedEvent(String account, String id) {
this.account = account;
this.id = id; this.id = id;
} }
} }

View File

@@ -289,6 +289,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
public void updateNotificationBadge() { public void updateNotificationBadge() {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID); AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain); Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
if (instance == null) return;
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance.pleroma != null) new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
.setCallback(new Callback<>() { .setCallback(new Callback<>() {
@@ -298,9 +299,6 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
try { try {
long newestId = Long.parseLong(notifications.get(0).id); long newestId = Long.parseLong(notifications.get(0).id);
long lastSeenId = Long.parseLong(session.markers.notifications.lastReadId); long lastSeenId = Long.parseLong(session.markers.notifications.lastReadId);
System.out.println("NEWEST: " + newestId);
System.out.println("LAST SEEN: " + lastSeenId);
setNotificationBadge(newestId > lastSeenId); setNotificationBadge(newestId > lastSeenId);
} catch (Exception ignored) { } catch (Exception ignored) {
setNotificationBadge(false); setNotificationBadge(false);
@@ -323,7 +321,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
@Subscribe @Subscribe
public void onNotificationReceived(NotificationReceivedEvent notificationReceivedEvent) { public void onNotificationReceived(NotificationReceivedEvent notificationReceivedEvent) {
setNotificationBadge(true); if (notificationReceivedEvent.account.equals(accountID)) setNotificationBadge(true);
} }
@Subscribe @Subscribe

View File

@@ -166,6 +166,10 @@ public class HomeTimelineFragment extends StatusListFragment {
} }
}) })
.exec(accountID); .exec(accountID);
if (parent.getParentFragment() instanceof HomeFragment homeFragment) {
homeFragment.updateNotificationBadge();
}
} }
@Override @Override

View File

@@ -15,6 +15,7 @@ import org.joinmastodon.android.events.AllNotificationsSeenEvent;
import org.joinmastodon.android.events.PollUpdatedEvent; import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent; import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Filter; import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Notification; import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse; import org.joinmastodon.android.model.PaginatedResponse;
@@ -128,7 +129,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
.getAccount(accountID).getCacheController() .getAccount(accountID).getCacheController()
.getNotifications(offset>0 ? maxID : null, count, onlyMentions, onlyPosts, refreshing, new SimpleCallback<>(this){ .getNotifications(offset>0 ? maxID : null, count, onlyMentions, onlyPosts, refreshing, new SimpleCallback<>(this){
@Override @Override
public void onSuccess(PaginatedResponse<List<Notification>> result){ public void onSuccess(CacheablePaginatedResponse<List<Notification>> result){
if (getActivity() == null) return; if (getActivity() == null) return;
if(refreshing) if(refreshing)
relationships.clear(); relationships.clear();
@@ -140,7 +141,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
loadRelationships(needRelationships); loadRelationships(needRelationships);
maxID=result.maxID; maxID=result.maxID;
if(offset==0 && !result.items.isEmpty()){ if(offset==0 && !result.items.isEmpty() && !result.isFromCache()){
E.post(new AllNotificationsSeenEvent()); E.post(new AllNotificationsSeenEvent());
new SaveMarkers(null, result.items.get(0).id).exec(accountID); new SaveMarkers(null, result.items.get(0).id).exec(accountID);
AccountSessionManager.getInstance().getAccount(accountID).markers AccountSessionManager.getInstance().getAccount(accountID).markers

View File

@@ -439,6 +439,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
toolbarTitleView.setTranslationY(titleTransY); toolbarTitleView.setTranslationY(titleTransY);
toolbarSubtitleView.setTranslationY(titleTransY); toolbarSubtitleView.setTranslationY(titleTransY);
} }
RecyclerFragment.setRefreshLayoutColors(refreshLayout);
} }
@Override @Override

View File

@@ -4,6 +4,8 @@ import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
@@ -25,7 +27,10 @@ public abstract class RecyclerFragment<T> extends BaseRecyclerFragment<T> {
public void onViewCreated(View view, Bundle savedInstanceState) { public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
Context ctx = getContext(); if (refreshLayout != null) setRefreshLayoutColors(refreshLayout);
}
public static void setRefreshLayoutColors(SwipeRefreshLayout l) {
List<Integer> colors = new ArrayList<>(Arrays.asList( List<Integer> colors = new ArrayList<>(Arrays.asList(
R.color.primary_600, R.color.primary_600,
R.color.red_primary_600, R.color.red_primary_600,
@@ -33,13 +38,13 @@ public abstract class RecyclerFragment<T> extends BaseRecyclerFragment<T> {
R.color.blue_primary_600, R.color.blue_primary_600,
R.color.purple_600 R.color.purple_600
)); ));
int primary = UiUtils.getThemeColorRes(ctx, R.attr.colorPrimary600); int primary = UiUtils.getThemeColorRes(l.getContext(), R.attr.colorPrimary600);
if (!colors.contains(primary)) colors.add(0, primary); if (!colors.contains(primary)) colors.add(0, primary);
int offset = colors.indexOf(primary); int offset = colors.indexOf(primary);
int[] sorted = new int[colors.size()]; int[] sorted = new int[colors.size()];
for (int i = 0; i < colors.size(); i++) { for (int i = 0; i < colors.size(); i++) {
sorted[i] = colors.get((i + offset) % colors.size()); sorted[i] = colors.get((i + offset) % colors.size());
} }
refreshLayout.setColorSchemeResources(sorted); l.setColorSchemeResources(sorted);
} }
} }

View File

@@ -151,7 +151,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){ protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream()) List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream())
.filter(s->s.account.id.equals(ev.postsByAccountID) || (s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID))) .filter(s->s.account.id.equals(ev.postsByAccountID) || (!ev.isUnfollow && s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
.collect(Collectors.toList()); .collect(Collectors.toList());
for(Status s:toRemove){ for(Status s:toRemove){
removeStatus(s); removeStatus(s);

View File

@@ -247,10 +247,11 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
altTextAnimator.cancel(); altTextAnimator.cancel();
View btn=controllers.get(altTextIndex).btnsWrap; View btn=controllers.get(altTextIndex).btnsWrap;
int i=0;
for(MediaAttachmentViewController c:controllers){ for(MediaAttachmentViewController c:controllers){
if(c.btnsWrap!=null && c.btnsWrap!=btn) { if(c.btnsWrap!=null && c.btnsWrap!=btn && !TextUtils.isEmpty(item.attachments.get(i).description))
c.btnsWrap.setVisibility(View.VISIBLE); c.btnsWrap.setVisibility(View.VISIBLE);
} i++;
} }
int[] loc={0, 0}; int[] loc={0, 0};

View File

@@ -32,23 +32,23 @@ import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
private CharSequence text, compactText; private CharSequence text;
@DrawableRes @DrawableRes
private int icon; private int icon;
private StatusPrivacy visibility; private StatusPrivacy visibility;
@DrawableRes @DrawableRes
private int iconEnd; private int iconEnd;
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(); private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(), fullTextEmojiHelper;
private View.OnClickListener handleClick; private View.OnClickListener handleClick;
boolean belowHeader, needBottomPadding; boolean belowHeader, needBottomPadding;
ReblogOrReplyLineStatusDisplayItem extra; ReblogOrReplyLineStatusDisplayItem extra;
String fullText; CharSequence fullText;
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick) { public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick) {
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, null); this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text);
} }
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, String fullText) { public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText) {
super(parentID, parentFragment); super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text); SpannableStringBuilder ssb=new SpannableStringBuilder(text);
HtmlParser.parseCustomEmoji(ssb, emojis); HtmlParser.parseCustomEmoji(ssb, emojis);
@@ -59,7 +59,15 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
TypedValue outValue = new TypedValue(); TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true); context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
updateVisibility(visibility); updateVisibility(visibility);
this.fullText = fullText;
if (fullText != null) {
fullTextEmojiHelper = new CustomEmojiHelper();
SpannableStringBuilder fullTextSsb = new SpannableStringBuilder(fullText);
HtmlParser.parseCustomEmoji(fullTextSsb, emojis);
this.fullText=fullTextSsb;
fullTextEmojiHelper.setText(fullTextSsb);
}
} }
public void updateVisibility(StatusPrivacy visibility) { public void updateVisibility(StatusPrivacy visibility) {

View File

@@ -0,0 +1,5 @@
- Favorisieren/Lesezeichen/Antworten direkt über Android-Benachrichtigungen
- Verbesserte Kopfzeilen für Reblogs und Antworten in der Timeline
- Benachrichtigungs-Punkt (Benachrichtigungen werden aktuell noch nicht automatisch nachgeladen)
- Für Akkoma-Benutzer_innen: Antwort-Sichtbarkeit, sortierte Thread-Antworten, Zitate, …
- Crashes behoben und kleinere Verbesserungen

View File

@@ -0,0 +1,5 @@
- Like/bookmark/reply directly from notification shade
- Prettier and more consistent headers for reblogs and replies in timeline
- Notification dot (which doesn't actually load the notifications just yet)
- For Akkoma users: Reply visibility, sorted thread replies, quoting, …
- Crash fixes and minor tweaks