Merge remote-tracking branch 'megalodon_main/main' into m3-merger

# Conflicts:
#	README.md
#	build.gradle
#	mastodon/build.gradle
#	mastodon/src/main/AndroidManifest.xml
#	mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java
#	mastodon/src/main/java/org/joinmastodon/android/MainActivity.java
#	mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java
#	mastodon/src/main/java/org/joinmastodon/android/api/requests/accounts/SetAccountMuted.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/AccountTimelineFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/EditTimelinesFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/PinnableStatusListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileAboutFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/SettingsFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/account_list/BaseAccountListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/CustomWelcomeFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/InstanceRulesFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/onboarding/OnboardingFollowSuggestionsFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/model/Attachment.java
#	mastodon/src/main/java/org/joinmastodon/android/model/Status.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/CustomEmojiPopupKeyboard.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/M3AlertDialogBuilder.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/AudioStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/PollOptionStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/utils/InsetStatusItemDecoration.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java
#	mastodon/src/main/res/color/button_bg_secondary_dark_on_light.xml
#	mastodon/src/main/res/color/button_text_primary_light_on_dark.xml
#	mastodon/src/main/res/drawable/bg_image_alt_text_overlay.xml
#	mastodon/src/main/res/drawable/bg_rect_4dp_ripple.xml
#	mastodon/src/main/res/drawable/bg_search_field.xml
#	mastodon/src/main/res/drawable/ic_fluent_save_24_regular.xml
#	mastodon/src/main/res/layout/compose_action.xml
#	mastodon/src/main/res/layout/compose_media_thumb.xml
#	mastodon/src/main/res/layout/compose_poll_option.xml
#	mastodon/src/main/res/layout/display_item_footer.xml
#	mastodon/src/main/res/layout/display_item_header.xml
#	mastodon/src/main/res/layout/display_item_text.xml
#	mastodon/src/main/res/layout/fragment_compose.xml
#	mastodon/src/main/res/layout/fragment_profile.xml
#	mastodon/src/main/res/layout/item_instance_category.xml
#	mastodon/src/main/res/layout/item_report_choice.xml
#	mastodon/src/main/res/layout/item_settings_footer.xml
#	mastodon/src/main/res/layout/item_settings_switch.xml
#	mastodon/src/main/res/layout/item_settings_theme.xml
#	mastodon/src/main/res/layout/item_settings_theme_subitem.xml
#	mastodon/src/main/res/layout/item_settings_update.xml
#	mastodon/src/main/res/layout/tab_bar.xml
#	mastodon/src/main/res/menu/mute_duration.xml
#	mastodon/src/main/res/values-de-rDE/strings_sk.xml
#	mastodon/src/main/res/values-es-rES/strings_sk.xml
#	mastodon/src/main/res/values-fa/strings_sk.xml
#	mastodon/src/main/res/values-night/colors.xml
#	mastodon/src/main/res/values-nl-rNL/strings_sk.xml
#	mastodon/src/main/res/values-uk-rUA/strings_sk.xml
#	mastodon/src/main/res/values-zh-rCN/strings_sk.xml
#	mastodon/src/main/res/values/attrs.xml
#	mastodon/src/main/res/values/ids.xml
#	mastodon/src/main/res/values/styles.xml
#	metadata/es/changelogs/83.txt
This commit is contained in:
LucasGGamerM
2023-08-20 11:36:16 -03:00
parent 8f4363a2d8
commit 93818903c8
753 changed files with 28298 additions and 14085 deletions

View File

@@ -5,7 +5,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.view.View;
@@ -26,15 +26,21 @@ import me.grishka.appkit.views.FragmentRootLinearLayout;
public class ElevationOnScrollListener extends RecyclerView.OnScrollListener implements View.OnScrollChangeListener{
private boolean isAtTop;
private Animator currentPanelsAnim;
private View[] views;
private List<View> views;
private View divider;
private FragmentRootLinearLayout fragmentRootLayout;
private Rect tmpRect=new Rect();
public ElevationOnScrollListener(FragmentRootLinearLayout fragmentRootLayout, View... views){
this(fragmentRootLayout, Arrays.asList(views));
}
public ElevationOnScrollListener(FragmentRootLinearLayout fragmentRootLayout, List<View> views){
isAtTop=true;
this.fragmentRootLayout=fragmentRootLayout;
this.views=views;
for(View v:views){
Drawable bg=v.getBackground().mutate();
Drawable bg=v.getContext().getDrawable(R.drawable.bg_onboarding_panel).mutate();
v.setBackground(bg);
if(bg instanceof LayerDrawable ld){
Drawable overlay=ld.findDrawableByLayerId(R.id.color_overlay);
@@ -45,13 +51,21 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
}
}
public void setDivider(View divider) {
this.divider = divider;
}
public void setViews(View... views){
List<View> oldViews=Arrays.asList(this.views);
setViews(Arrays.asList(views));
}
public void setViews(List<View> views){
List<View> oldViews=this.views;
this.views=views;
for(View v:views){
if(oldViews.contains(v))
continue;
Drawable bg=v.getBackground().mutate();
Drawable bg=v.getContext().getDrawable(R.drawable.bg_onboarding_panel).mutate();
v.setBackground(bg);
if(bg instanceof LayerDrawable ld){
Drawable overlay=ld.findDrawableByLayerId(R.id.color_overlay);
@@ -63,9 +77,14 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
}
}
private int getRecyclerChildDecoratedTop(RecyclerView rv, View child){
rv.getDecoratedBoundsWithMargins(child, tmpRect);
return tmpRect.top;
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
boolean newAtTop=recyclerView.getChildCount()==0 || (recyclerView.getChildAdapterPosition(recyclerView.getChildAt(0))==0 && recyclerView.getChildAt(0).getTop()==recyclerView.getPaddingTop());
boolean newAtTop=recyclerView.getChildCount()==0 || (recyclerView.getChildAdapterPosition(recyclerView.getChildAt(0))==0 && getRecyclerChildDecoratedTop(recyclerView, recyclerView.getChildAt(0))==recyclerView.getPaddingTop());
handleScroll(recyclerView.getContext(), newAtTop);
}
@@ -74,7 +93,8 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
handleScroll(v.getContext(), scrollY<=0);
}
private void handleScroll(Context context, boolean newAtTop){
public void handleScroll(Context context, boolean newAtTop){
if(UiUtils.isTrueBlackTheme()) newAtTop=true;
if(newAtTop!=isAtTop){
isAtTop=newAtTop;
if(currentPanelsAnim!=null)
@@ -86,20 +106,23 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
if(v.getBackground() instanceof LayerDrawable ld){
Drawable overlay=ld.findDrawableByLayerId(R.id.color_overlay);
if(overlay!=null){
anims.add(ObjectAnimator.ofInt(overlay, "alpha", isAtTop ? 0 : 20));
anims.add(ObjectAnimator.ofInt(overlay, "alpha", newAtTop ? 0 : 20));
}
}
anims.add(ObjectAnimator.ofFloat(v, View.TRANSLATION_Z, isAtTop ? 0 : V.dp(3)));
anims.add(ObjectAnimator.ofFloat(v, View.TRANSLATION_Z, newAtTop ? 0 : V.dp(3)));
}
if(fragmentRootLayout!=null){
int color;
if(isAtTop){
color=UiUtils.getThemeColor(context, R.attr.toolbarBackground);
if(newAtTop){
color=UiUtils.getThemeColor(context, R.attr.colorM3Background);
}else{
color=UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.toolbarBackground), UiUtils.getThemeColor(context, R.attr.colorWindowBackground), 0.07843137f);
color=UiUtils.alphaBlendColors(UiUtils.getThemeColor(context, R.attr.colorM3Background), UiUtils.getThemeColor(context, R.attr.colorM3Primary), 0.07843137f);
}
anims.add(ObjectAnimator.ofArgb(fragmentRootLayout, "statusBarColor", color));
}
if(divider!=null){
anims.add(ObjectAnimator.ofFloat(divider, View.ALPHA, newAtTop ? 1 : 0));
}
set.playTogether(anims);
set.setDuration(150);
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
@@ -113,4 +136,8 @@ public class ElevationOnScrollListener extends RecyclerView.OnScrollListener imp
currentPanelsAnim=set;
}
}
public int getCurrentStatusBarColor(){
return fragmentRootLayout.getStatusBarColor();
}
}

View File

@@ -3,12 +3,14 @@ package org.joinmastodon.android.utils;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.os.LocaleList;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.Instance;
import org.parceler.Parcel;
import java.util.ArrayList;
import java.util.Collections;
@@ -16,8 +18,10 @@ import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;
@Parcel
public class MastodonLanguage {
// On an up-to-date Mastodon instance:
// copy(JSON.stringify(JSON.stringify(JSON.parse(document.getElementById('initial-state').textContent).languages)))
@@ -50,10 +54,12 @@ public class MastodonLanguage {
.collect(Collectors.toList());
}
public final String languageTag, name, englishName;
public final Locale locale;
public String languageTag, name, englishName;
public Locale locale;
private MastodonLanguage(String languageTag, String englishName, String name) {
protected MastodonLanguage() {}
protected MastodonLanguage(String languageTag, String englishName, String name) {
this.locale = new Locale(languageTag);
this.languageTag = languageTag.toLowerCase(Locale.ROOT);
this.name = name;
@@ -69,6 +75,10 @@ public class MastodonLanguage {
public String getLanguage() { return languageTag; }
public String getDisplayName(Context context) {
return context.getString(R.string.sk_language_name, getDefaultName(), getLanguageName());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -91,14 +101,18 @@ public class MastodonLanguage {
.orElse(ENGLISH);
}
public MastodonLanguage from(String language) {
public MastodonLanguage fromOrFallback(String language) {
return from(language).orElse(fallbackLanguage);
}
public Optional<MastodonLanguage> from(String language) {
return allLanguages.stream()
.filter(l->l.locale.equals(new Locale(language))).findAny()
.orElse(fallbackLanguage);
.filter(l->l.locale.equals(new Locale(language)))
.findAny();
}
public MastodonLanguage getDefault() {
return from(Locale.getDefault().getLanguage());
return fromOrFallback(Locale.getDefault().getLanguage());
}
}
}

View File

@@ -0,0 +1,18 @@
package org.joinmastodon.android.utils;
import java.util.Comparator;
public class ObjectIdComparator implements Comparator<String>{
public static final ObjectIdComparator INSTANCE=new ObjectIdComparator();
@Override
public int compare(String o1, String o2){
int l1=o1==null ? 0 : o1.length();
int l2=o2==null ? 0 : o2.length();
if(l1!=l2)
return Integer.compare(l1, l2);
if(l1==0)
return 0;
return o1.compareTo(o2);
}
}

View File

@@ -1,7 +1,9 @@
package org.joinmastodon.android.utils;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.LegacyFilter;
import org.joinmastodon.android.model.FilterAction;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status;
import java.time.Instant;
@@ -12,24 +14,24 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StatusFilterPredicate implements Predicate<Status>{
private final List<Filter> filters;
private final Filter.FilterContext context;
private final Filter.FilterAction action;
private Filter applyingFilter;
private final List<LegacyFilter> filters;
private final FilterContext context;
private final FilterAction action;
private LegacyFilter applyingFilter;
/**
* @param context null makes the predicate pass automatically
* @param action defines what the predicate should check:
* status should not be hidden or should not display with warning
*/
public StatusFilterPredicate(List<Filter> filters, Filter.FilterContext context, Filter.FilterAction action){
public StatusFilterPredicate(List<LegacyFilter> filters, FilterContext context, FilterAction action){
this.filters = filters;
this.context = context;
this.action = action;
}
public StatusFilterPredicate(List<Filter> filters, Filter.FilterContext context){
this(filters, context, Filter.FilterAction.HIDE);
public StatusFilterPredicate(List<LegacyFilter> filters, FilterContext context){
this(filters, context, FilterAction.HIDE);
}
/**
@@ -37,7 +39,7 @@ public class StatusFilterPredicate implements Predicate<Status>{
* @param action defines what the predicate should check:
* status should not be hidden or should not display with warning
*/
public StatusFilterPredicate(String accountID, Filter.FilterContext context, Filter.FilterAction action){
public StatusFilterPredicate(String accountID, FilterContext context, FilterAction action){
filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(context)).collect(Collectors.toList());
this.context = context;
this.action = action;
@@ -46,8 +48,8 @@ public class StatusFilterPredicate implements Predicate<Status>{
/**
* @param context null makes the predicate pass automatically
*/
public StatusFilterPredicate(String accountID, Filter.FilterContext context){
this(accountID, context, Filter.FilterAction.HIDE);
public StatusFilterPredicate(String accountID, FilterContext context){
this(accountID, context, FilterAction.HIDE);
}
/**
@@ -60,26 +62,26 @@ public class StatusFilterPredicate implements Predicate<Status>{
public boolean test(Status status){
if (context == null) return true;
Stream<Filter> matchingFilters = status.filtered != null
Stream<LegacyFilter> matchingFilters = status.filtered != null
// use server-provided per-status info (status.filtered) if available
? status.filtered.stream().map(f -> f.filter)
// or fall back to cached filters
: filters.stream().filter(filter -> filter.matches(status));
Optional<Filter> applyingFilter = matchingFilters
Optional<LegacyFilter> applyingFilter = matchingFilters
// discard expired filters
.filter(filter -> filter.expiresAt == null || filter.expiresAt.isAfter(Instant.now()))
// only apply filters for given context
.filter(filter -> filter.context.contains(context))
// treating filterAction = null (from filters list) as FilterAction.HIDE
.filter(filter -> filter.filterAction == null ? action == Filter.FilterAction.HIDE : filter.filterAction == action)
.filter(filter -> filter.filterAction == null ? action == FilterAction.HIDE : filter.filterAction == action)
.findAny();
this.applyingFilter = applyingFilter.orElse(null);
return applyingFilter.isEmpty();
}
public Filter getApplyingFilter() {
public LegacyFilter getApplyingFilter() {
return applyingFilter;
}
}

View File

@@ -0,0 +1,31 @@
package org.joinmastodon.android.utils;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.ViewImageLoader;
public class ViewImageLoaderHolderTarget implements ViewImageLoader.Target{
private final ImageLoaderViewHolder holder;
private final int imageIndex;
public ViewImageLoaderHolderTarget(ImageLoaderViewHolder holder, int imageIndex){
this.holder=holder;
this.imageIndex=imageIndex;
}
@Override
public void setImageDrawable(Drawable d){
if(d==null)
holder.clearImage(imageIndex);
else
holder.setImage(imageIndex, d);
}
@Override
public View getView(){
return ((RecyclerView.ViewHolder)holder).itemView;
}
}