diff --git a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java index ca36903ac..4524c8cef 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java +++ b/mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java @@ -34,7 +34,6 @@ public class GlobalUserPreferences{ public static boolean useCustomTabs; public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost; public static ThemePreference theme; - public static LoadMissingPostsPreference loadMissingPosts; // MEGALODON public static boolean trueBlackTheme; @@ -124,7 +123,6 @@ public class GlobalUserPreferences{ displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true); overlayMedia=prefs.getBoolean("overlayMedia", false); showSuicideHelp=prefs.getBoolean("showSuicideHelp", true); - loadMissingPosts=LoadMissingPostsPreference.values()[prefs.getInt("loadMissingItems", 0)]; if (prefs.contains("prefixRepliesWithRe")) { prefixReplies = prefs.getBoolean("prefixRepliesWithRe", false) @@ -184,7 +182,6 @@ public class GlobalUserPreferences{ .putBoolean("displayPronounsInUserListings", displayPronounsInUserListings) .putBoolean("overlayMedia", overlayMedia) .putBoolean("showSuicideHelp", showSuicideHelp) - .putInt("loadMissingItems", loadMissingPosts.ordinal()) .apply(); } @@ -279,16 +276,4 @@ public class GlobalUserPreferences{ ALWAYS, TO_OTHERS } - - public enum LoadMissingPostsPreference{ - NEWEST_FIRST(R.string.sk_load_missing_posts_newest_first), // Downwards, default - OLDEST_FIRST(R.string.sk_load_missing_posts_oldest_first); // Upwards - - @StringRes - public int labelRes; - - LoadMissingPostsPreference(@StringRes int labelRes){ - this.labelRes=labelRes; - } - } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java index 0cb77d37d..da2f43242 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -617,7 +617,7 @@ public abstract class BaseStatusListFragment exten } } - public void onGapClick(GapStatusDisplayItem.Holder item){} + public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){} public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){ int startPos = warning.getAbsoluteAdapterPosition(); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 9a70f75e4..92d0bb076 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -8,23 +8,18 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; -import org.joinmastodon.android.E; import org.joinmastodon.android.GlobalUserPreferences; -import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.markers.SaveMarkers; import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline; import org.joinmastodon.android.api.session.AccountLocalPreferences; import org.joinmastodon.android.api.session.AccountSessionManager; -import org.joinmastodon.android.events.StatusCreatedEvent; import org.joinmastodon.android.model.CacheablePaginatedResponse; import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.TimelineMarkers; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; -import org.joinmastodon.android.utils.StatusFilterPredicate; -import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; @@ -36,7 +31,6 @@ import java.util.stream.Collectors; import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.SimpleCallback; -import me.grishka.appkit.utils.V; public class HomeTimelineFragment extends StatusListFragment { private HomeTabFragment parent; @@ -181,19 +175,16 @@ public class HomeTimelineFragment extends StatusListFragment { } @Override - public void onGapClick(GapStatusDisplayItem.Holder item){ + public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){ if(dataLoading) return; GapStatusDisplayItem gap=item.getItem(); gap.loading=true; - V.setVisibilityAnimated(item.progress, View.VISIBLE); - V.setVisibilityAnimated(item.text, View.GONE); dataLoading=true; - GlobalUserPreferences.LoadMissingPostsPreference preference = GlobalUserPreferences.loadMissingPosts; String maxID = null; String minID = null; - if (preference==GlobalUserPreferences.LoadMissingPostsPreference.NEWEST_FIRST) { + if (downwards) { maxID = item.getItemID(); } else { int gapPos=displayItems.indexOf(gap); @@ -220,7 +211,7 @@ public class HomeTimelineFragment extends StatusListFragment { AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false); } }else{ - if(preference==GlobalUserPreferences.LoadMissingPostsPreference.NEWEST_FIRST) { + if(downwards) { Set idsBelowGap=new HashSet<>(); boolean belowGap=false; int gapPostIndex=0; diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusEditHistoryFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusEditHistoryFragment.java index f3e7b3d49..aa52dda9a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusEditHistoryFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusEditHistoryFragment.java @@ -144,7 +144,7 @@ public class StatusEditHistoryFragment extends StatusListFragment{ } } String sep = getString(R.string.sk_separator); - items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" "+sep+" "+date, Collections.emptyList(), 0, null, null)); + items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" "+sep+" "+date, Collections.emptyList(), 0, null, null, s)); items.add(1, new DummyStatusDisplayItem(s.id, this)); } return items; diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java index 2c28bd37c..e947519aa 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsBehaviorFragment.java @@ -23,7 +23,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; public class SettingsBehaviorFragment extends BaseSettingsFragment implements HasAccountID{ - private ListItem languageItem, loadMissingPostsItem; + private ListItem languageItem; private CheckableListItem altTextItem, playGifsItem, customTabsItem, confirmUnfollowItem, confirmBoostItem, confirmDeleteItem; private MastodonLanguage postLanguage; private ComposeLanguageAlertViewController.SelectedOption newPostLanguage; @@ -46,7 +46,6 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment impleme List> items = new ArrayList<>(List.of( languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick), - loadMissingPostsItem=new ListItem<>(R.string.sk_settings_load_missing_posts, GlobalUserPreferences.loadMissingPosts.labelRes, R.drawable.ic_fluent_arrow_maximize_vertical_24_regular, this::onLoadMissingPostsClick), altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, ()->toggleCheckableItem(altTextItem)), playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, ()->toggleCheckableItem(playGifsItem)), overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, ()->toggleCheckableItem(overlayMediaItem)), @@ -129,27 +128,6 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment impleme .show(); } - private void onLoadMissingPostsClick(){ - GlobalUserPreferences.LoadMissingPostsPreference[] values=GlobalUserPreferences.LoadMissingPostsPreference.values(); - int selected=GlobalUserPreferences.loadMissingPosts.ordinal(); - int[] newSelected={selected}; - new M3AlertDialogBuilder(getActivity()) - .setTitle(R.string.sk_settings_load_missing_posts) - .setSingleChoiceItems(Stream.of(values).map(pref->getString(pref.labelRes)).toArray(String[]::new), - selected, (dlg, item)->newSelected[0]=item) - .setPositiveButton(R.string.ok, (dlg, item)->{ - GlobalUserPreferences.LoadMissingPostsPreference pref=values[newSelected[0]]; - if(pref!=GlobalUserPreferences.loadMissingPosts){ - GlobalUserPreferences.loadMissingPosts=pref; - GlobalUserPreferences.save(); - loadMissingPostsItem.subtitleRes=pref.labelRes; - rebindItem(loadMissingPostsItem); - } - }) - .setNegativeButton(R.string.cancel, null) - .show(); - } - private void onReplyVisibilityClick(){ AccountLocalPreferences lp=getLocalPrefs(); int selected=lp.timelineReplyVisibility==null ? 2 : switch(lp.timelineReplyVisibility){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java index b4196d622..378728911 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java @@ -1,5 +1,8 @@ package org.joinmastodon.android.ui.displayitems; +import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn; +import static org.joinmastodon.android.ui.utils.UiUtils.opacityOut; + import android.app.Activity; import android.app.Dialog; import android.content.Context; @@ -12,8 +15,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.accessibility.AccessibilityNodeInfo; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; import android.widget.Button; import android.widget.FrameLayout; import android.widget.TextView; @@ -56,7 +57,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ public static class Holder extends StatusDisplayItem.Holder{ private final TextView replies, boosts, favorites; private final View reply, boost, favorite, share, bookmark; - private static final Animation opacityOut, opacityIn; private View touchingView = null; private boolean longClickPerformed = false; @@ -77,18 +77,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{ } }; - private static final float ALPHA_PRESSED=0.55f; - - static { - opacityOut = new AlphaAnimation(1, ALPHA_PRESSED); - opacityOut.setDuration(300); - opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT); - opacityOut.setFillAfter(true); - opacityIn = new AlphaAnimation(ALPHA_PRESSED, 1); - opacityIn.setDuration(400); - opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT); - } - public Holder(Activity activity, ViewGroup parent){ super(activity, R.layout.display_item_footer, parent); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/GapStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/GapStatusDisplayItem.java index 7c325f658..1009bb148 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/GapStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/GapStatusDisplayItem.java @@ -8,14 +8,21 @@ import android.widget.TextView; import org.joinmastodon.android.R; import org.joinmastodon.android.fragments.BaseStatusListFragment; +import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable; +import org.joinmastodon.android.ui.utils.UiUtils; + +import java.time.Instant; + +import me.grishka.appkit.utils.V; -// Mind the gap! public class GapStatusDisplayItem extends StatusDisplayItem{ public boolean loading; + private Status status; - public GapStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment){ + public GapStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status){ super(parentID, parentFragment); + this.status=status; } @Override @@ -24,25 +31,53 @@ public class GapStatusDisplayItem extends StatusDisplayItem{ } public static class Holder extends StatusDisplayItem.Holder{ - public final ProgressBar progress; - public final TextView text; + public final ProgressBar progressTop, progressBottom; + public final TextView textTop, gap, textBottom; + public final View top, bottom; public Holder(Context context, ViewGroup parent){ super(context, R.layout.display_item_gap, parent); - progress=findViewById(R.id.progress); - text=findViewById(R.id.text); - itemView.setForeground(new SawtoothTearDrawable(context)); + progressTop=findViewById(R.id.progress_top); + progressBottom=findViewById(R.id.progress_bottom); + textTop=findViewById(R.id.text_top); + textBottom=findViewById(R.id.text_bottom); + top=findViewById(R.id.top); + top.setOnClickListener(this::onViewClick); + bottom=findViewById(R.id.bottom); + bottom.setOnClickListener(this::onViewClick); + gap=findViewById(R.id.gap); + gap.setForeground(new SawtoothTearDrawable(context)); } @Override public void onBind(GapStatusDisplayItem item){ - text.setVisibility(item.loading ? View.GONE : View.VISIBLE); - progress.setVisibility(item.loading ? View.VISIBLE : View.GONE); + if(!item.loading){ + progressBottom.setVisibility(View.GONE); + progressTop.setVisibility(View.GONE); + } + top.setClickable(!item.loading); + bottom.setClickable(!item.loading); + StatusDisplayItem next=getNextVisibleDisplayItem().orElse(null); + Instant dateBelow=next instanceof HeaderStatusDisplayItem h ? h.status.createdAt + : next instanceof ReblogOrReplyLineStatusDisplayItem l ? l.status.createdAt + : null; + String text=dateBelow!=null && item.status.createdAt!=null && dateBelow.isBefore(item.status.createdAt) + ? UiUtils.formatPeriodBetween(item.parentFragment.getContext(), dateBelow, item.status.createdAt) + : null; + gap.setText(text); + int p=text==null ? V.dp(6) : V.dp(20); + gap.setPadding(p, p, p, p); + } + + private void onViewClick(View v){ + if(item.loading) return; + boolean isTop=v==top; + (isTop ? textTop : textBottom).startAnimation(UiUtils.opacityOut); + V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE); + item.parentFragment.onGapClick(this, isTop); } @Override - public void onClick(){ - item.parentFragment.onGapClick(this); - } + public void onClick(){} } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java index 0e87b656d..097aae9f0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/ReblogOrReplyLineStatusDisplayItem.java @@ -17,6 +17,7 @@ import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.R; import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.model.Emoji; +import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.utils.CustomEmojiHelper; @@ -43,18 +44,20 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{ public boolean needBottomPadding; ReblogOrReplyLineStatusDisplayItem extra; CharSequence fullText; + Status status; - public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick) { - this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text); + public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, Status status) { + this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text, status); } - public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText) { + public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText, Status status) { super(parentID, parentFragment); SpannableStringBuilder ssb=new SpannableStringBuilder(text); HtmlParser.parseCustomEmoji(ssb, emojis); this.text=ssb; emojiHelper.setText(ssb); this.icon=icon; + this.status=status; this.handleClick=handleClick; TypedValue outValue = new TypedValue(); context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true); diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java index e17b1f49a..cdc663c6a 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java @@ -135,7 +135,7 @@ public abstract class StatusDisplayItem{ : fragment.getString(R.string.in_reply_to, account.displayName); return new ReblogOrReplyLineStatusDisplayItem( parentID, fragment, text, account == null ? List.of() : account.emojis, - R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText + R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status ); } @@ -167,7 +167,7 @@ public abstract class StatusDisplayItem{ items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{ args.putParcelable("profileAccount", Parcels.wrap(status.account)); Nav.go(fragment.getActivity(), ProfileFragment.class, args); - }, fullText)); + }, fullText, status)); } else if (!(status.tags.isEmpty() || fragment instanceof HashtagTimelineFragment || fragment instanceof ListTimelineFragment @@ -183,7 +183,7 @@ public abstract class StatusDisplayItem{ i -> { args.putString("hashtag", hashtag.name); Nav.go(fragment.getActivity(), HashtagTimelineFragment.class, args); - } + }, status ))); } @@ -294,7 +294,7 @@ public abstract class StatusDisplayItem{ footer.hideCounts=hideCounts; items.add(footer); if(status.hasGapAfter && !(fragment instanceof ThreadFragment)) - items.add(new GapStatusDisplayItem(parentID, fragment)); + items.add(new GapStatusDisplayItem(parentID, fragment, status)); } int i=1; boolean inset=(flags & FLAG_INSET)!=0; diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/drawables/SawtoothTearDrawable.java b/mastodon/src/main/java/org/joinmastodon/android/ui/drawables/SawtoothTearDrawable.java index 1100fd950..a461646dc 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/drawables/SawtoothTearDrawable.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/drawables/SawtoothTearDrawable.java @@ -23,9 +23,9 @@ import me.grishka.appkit.utils.V; public class SawtoothTearDrawable extends Drawable{ private final Paint topPaint, bottomPaint; - private static final int TOP_SAWTOOTH_HEIGHT=5; - private static final int BOTTOM_SAWTOOTH_HEIGHT=3; - private static final int STROKE_WIDTH=2; + private static final int TOP_SAWTOOTH_HEIGHT=4; + private static final int BOTTOM_SAWTOOTH_HEIGHT=4; + private static final int STROKE_WIDTH=1; private static final int SAWTOOTH_PERIOD=14; public SawtoothTearDrawable(Context context){ diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index eae6682ef..673df5b0b 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -54,6 +54,8 @@ import android.view.SubMenu; import android.view.View; import android.view.ViewGroup; import android.view.WindowInsets; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; import android.webkit.MimeTypeMap; import android.widget.Button; import android.widget.ImageView; @@ -96,7 +98,6 @@ import org.joinmastodon.android.fragments.ComposeFragment; import org.joinmastodon.android.fragments.HashtagTimelineFragment; import org.joinmastodon.android.fragments.ProfileFragment; import org.joinmastodon.android.fragments.ThreadFragment; -import org.joinmastodon.android.fragments.settings.SettingsServerAboutFragment; import org.joinmastodon.android.fragments.settings.SettingsServerFragment; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.AccountField; @@ -173,6 +174,19 @@ public class UiUtils { private static final DateTimeFormatter TIME_FORMATTER=DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT); public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA; + public static final float ALPHA_PRESSED=0.55f; + public static final Animation opacityOut, opacityIn; + + static { + opacityOut = new AlphaAnimation(1, ALPHA_PRESSED); + opacityOut.setDuration(300); + opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT); + opacityOut.setFillAfter(true); + opacityIn = new AlphaAnimation(ALPHA_PRESSED, 1); + opacityIn.setDuration(400); + opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT); + } + private UiUtils() { } @@ -192,28 +206,33 @@ public class UiUtils { } public static String formatRelativeTimestamp(Context context, Instant instant) { - long t = instant.toEpochMilli(); - long now = System.currentTimeMillis(); + return formatPeriodBetween(context, instant, null); + } + + public static String formatPeriodBetween(Context context, Instant since, Instant until) { + boolean ago = until == null; + long t = since.toEpochMilli(); + long now = ago ? System.currentTimeMillis() : until.toEpochMilli(); long diff = now - t; if(diff<1000L){ return context.getString(R.string.time_now); }else if(diff<60_000L){ - return context.getString(R.string.time_seconds_ago_short, diff/1000L); + return context.getString(ago ? R.string.time_seconds_ago_short : R.string.sk_time_seconds, diff/1000L); }else if(diff<3600_000L){ - return context.getString(R.string.time_minutes_ago_short, diff/60_000L); + return context.getString(ago ? R.string.time_minutes_ago_short : R.string.sk_time_minutes, diff/60_000L); }else if(diff<3600_000L*24L){ - return context.getString(R.string.time_hours_ago_short, diff/3600_000L); + return context.getString(ago ? R.string.time_hours_ago_short : R.string.sk_time_hours, diff/3600_000L); } else { int days = (int) (diff / (3600_000L * 24L)); - if (days > 30) { - ZonedDateTime dt = instant.atZone(ZoneId.systemDefault()); + if (ago && days > 30) { + ZonedDateTime dt = since.atZone(ZoneId.systemDefault()); if (dt.getYear() == ZonedDateTime.now().getYear()) { return DATE_FORMATTER_SHORT.format(dt); } else { return DATE_FORMATTER_SHORT_WITH_YEAR.format(dt); } } - return context.getString(R.string.time_days_ago_short, days); + return context.getString(ago ? R.string.time_days_ago_short : R.string.sk_time_days, days); } } diff --git a/mastodon/src/main/res/drawable/bg_timeline_gap.xml b/mastodon/src/main/res/drawable/bg_timeline_gap.xml index 1536ca15d..c14028dc5 100644 --- a/mastodon/src/main/res/drawable/bg_timeline_gap.xml +++ b/mastodon/src/main/res/drawable/bg_timeline_gap.xml @@ -1,7 +1,6 @@ - + - \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/bg_timeline_gap_border.xml b/mastodon/src/main/res/drawable/bg_timeline_gap_border.xml new file mode 100644 index 000000000..d782ee72a --- /dev/null +++ b/mastodon/src/main/res/drawable/bg_timeline_gap_border.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_fluent_chevron_double_down_20_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_chevron_double_down_20_filled.xml new file mode 100644 index 000000000..832130b0d --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_chevron_double_down_20_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_chevron_double_up_20_filled.xml b/mastodon/src/main/res/drawable/ic_fluent_chevron_double_up_20_filled.xml new file mode 100644 index 000000000..cb1915942 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_chevron_double_up_20_filled.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/layout/display_item_gap.xml b/mastodon/src/main/res/layout/display_item_gap.xml index cbc06a8b7..a2e904154 100644 --- a/mastodon/src/main/res/layout/display_item_gap.xml +++ b/mastodon/src/main/res/layout/display_item_gap.xml @@ -1,24 +1,79 @@ - + android:layout_height="wrap_content" + android:orientation="vertical" + android:background="@drawable/bg_timeline_gap_border"> - + android:layout_marginBottom="4dp" + android:background="?android:selectableItemBackground"> - + - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml index 08260a7a3..45c966eca 100644 --- a/mastodon/src/main/res/values/strings_sk.xml +++ b/mastodon/src/main/res/values/strings_sk.xml @@ -388,4 +388,10 @@ Load missing posts behavior Newest first (downwards) Oldest first (upwards) + Load newer posts + Load older posts + %d seconds + %d minutes + %d hours + %d days \ No newline at end of file