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:
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user