diff --git a/app/build.gradle b/app/build.gradle index 4ab8912d..ef78a3c7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,8 +13,8 @@ android { defaultConfig { minSdk 21 targetSdk 32 - versionCode 439 - versionName "3.9.4" + versionCode 443 + versionName "3.10.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } flavorDimensions "default" @@ -79,7 +79,11 @@ allprojects { dependencies { implementation project(':autoimageslider') implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'com.google.android.material:material:1.7.0' + + implementation 'com.jaredrummler:colorpicker:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "com.google.code.gson:gson:2.9.1" implementation 'com.squareup.retrofit2:retrofit:2.9.0' diff --git a/app/src/main/assets/release_notes/notes.json b/app/src/main/assets/release_notes/notes.json index 3a01fdff..0a3ee24c 100644 --- a/app/src/main/assets/release_notes/notes.json +++ b/app/src/main/assets/release_notes/notes.json @@ -1,4 +1,24 @@ [ + { + "version": "3.10.0", + "code": "443", + "note": "Added:\n- Dracula theme\n- Customize message colors\n- Enable/Disable Card presentation\n\nChanged:\n- Colors for some themes\n- Space between buttons\n\nFixed:\n- Animated profile pictures not displayed\n- Mentions broken in profile bio and fields\n- Jumps with fit preview images when scrolling up\n- Fetch more button broken with cache\n- Tag patterns in URL break the link\n- Typo in followed tags" + }, + { + "version": "3.9.7", + "code": "442", + "note": "Added:\n- Dracula theme\n\nChanged:\n- Colors for Light/Dark/Black themes\n\nFixed:\n- Animated profile pictures not displayed\n- Mentions broken in profile bio and fields\n- Tag patterns in URL break the link\n- Typo in followed tags" + }, + { + "version": "3.9.6", + "code": "441", + "note": "Fixed:\n- Jumps with fit preview images when scrolling up\n- Fetch more button broken with cache" + }, + { + "version": "3.9.5", + "code": "440", + "note": "Fixed:\n- Custom emoji are not always displayed\n- Jumps in timeline when using \"fit preview images\"\n- Dark theme: timeline buttons without toggle" + }, { "version": "3.9.4", "code": "439", diff --git a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java index be483f80..2f2b870f 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseActivity.java @@ -83,6 +83,10 @@ public class BaseActivity extends AppCompatActivity { setTheme(R.style.BlackAppTheme); currentThemeId = R.style.BlackAppTheme; break; + case "DRACULA": + setTheme(R.style.DraculaAppTheme); + currentThemeId = R.style.DraculaAppTheme; + break; } break; } @@ -113,6 +117,11 @@ public class BaseActivity extends AppCompatActivity { setTheme(R.style.BlackAppTheme); currentThemeId = R.style.BlackAppTheme; break; + case "DRACULA": + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + setTheme(R.style.DraculaAppTheme); + currentThemeId = R.style.DraculaAppTheme; + break; } } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java index 220526dc..48b51a25 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseAlertDialogActivity.java @@ -76,6 +76,9 @@ public class BaseAlertDialogActivity extends AppCompatActivity { case "BLACK": setTheme(R.style.BlackAlertDialog); break; + case "DRACULA": + setTheme(R.style.DraculaAlertDialog); + break; } break; } @@ -101,6 +104,10 @@ public class BaseAlertDialogActivity extends AppCompatActivity { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); setTheme(R.style.BlackAlertDialog); break; + case "DRACULA": + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + setTheme(R.style.DraculaAlertDialog); + break; } } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java index dce37269..e8f0111e 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseBarActivity.java @@ -75,6 +75,9 @@ public class BaseBarActivity extends AppCompatActivity { case "BLACK": setTheme(R.style.BlackAppThemeBar); break; + case "DRACULA": + setTheme(R.style.DraculaAppThemeBar); + break; } break; } @@ -101,6 +104,10 @@ public class BaseBarActivity extends AppCompatActivity { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); setTheme(R.style.BlackAppThemeBar); break; + case "DRACULA": + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + setTheme(R.style.DraculaAppThemeBar); + break; } } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java index 12f89e80..77f2df73 100644 --- a/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/BaseTransparentActivity.java @@ -75,6 +75,9 @@ public class BaseTransparentActivity extends AppCompatActivity { case "BLACK": setTheme(R.style.TransparentBlack); break; + case "DRACULA": + setTheme(R.style.TransparentDracula); + break; } break; } @@ -101,6 +104,10 @@ public class BaseTransparentActivity extends AppCompatActivity { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); setTheme(R.style.TransparentBlack); break; + case "DRACULA": + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + setTheme(R.style.TransparentDracula); + break; } } super.onCreate(savedInstanceState); diff --git a/app/src/main/java/app/fedilab/android/activities/FollowedTagActivity.java b/app/src/main/java/app/fedilab/android/activities/FollowedTagActivity.java index 8dbd904d..bd5732e3 100644 --- a/app/src/main/java/app/fedilab/android/activities/FollowedTagActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/FollowedTagActivity.java @@ -108,7 +108,7 @@ public class FollowedTagActivity extends BaseBarActivity implements FollowedTagA fragmentMastodonTimeline.onDestroyView(); } invalidateOptionsMenu(); - setTitle(R.string.action_lists); + setTitle(R.string.followed_tags); }); if (tagList.size() == 0) { binding.notContent.setVisibility(View.VISIBLE); @@ -177,7 +177,7 @@ public class FollowedTagActivity extends BaseBarActivity implements FollowedTagA fragmentMastodonTimeline.onDestroyView(); } }); - setTitle(R.string.action_lists); + setTitle(R.string.followed_tags); invalidateOptionsMenu(); } else { super.onBackPressed(); diff --git a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java index 01afc9ce..5c34875e 100644 --- a/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/ProfileActivity.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.res.ColorStateList; +import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.text.SpannableString; @@ -262,6 +263,7 @@ public class ProfileActivity extends BaseActivity { }); boolean disableGif = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_GIF), false); String targetedUrl = disableGif ? account.avatar_static : account.avatar; + // MastodonHelper.loadPPMastodon(binding.accountPp, account); Glide.with(ProfileActivity.this) .asDrawable() .dontTransform() @@ -271,6 +273,11 @@ public class ProfileActivity extends BaseActivity { public void onResourceReady(@NonNull final Drawable resource, Transition transition) { binding.profilePicture.setImageDrawable(resource); binding.accountPp.setImageDrawable(resource); + if (resource instanceof Animatable) { + binding.profilePicture.animate(); + binding.accountPp.animate(); + ((Animatable) resource).start(); + } ActivityCompat.startPostponedEnterTransition(ProfileActivity.this); } @@ -390,7 +397,7 @@ public class ProfileActivity extends BaseActivity { TextView.BufferType.SPANNABLE); binding.accountNote.setMovementMethod(LinkMovementMethod.getInstance()); - //MastodonHelper.loadPPMastodon(binding.accountPp, account); + binding.accountPp.setOnClickListener(v -> { Intent intent = new Intent(ProfileActivity.this, MediaActivity.class); Bundle b = new Bundle(); @@ -935,13 +942,11 @@ public class ProfileActivity extends BaseActivity { builderInner.setTitle(stringArrayConf[0]); builderInner.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss()); - builderInner.setNegativeButton(R.string.keep_notifications, (dialog, which) -> { - accountsVM.mute(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, target, false, 0) - .observe(ProfileActivity.this, relationShip -> { - this.relationship = relationShip; - updateAccount(); - }); - }); + builderInner.setNegativeButton(R.string.keep_notifications, (dialog, which) -> accountsVM.mute(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, target, false, 0) + .observe(ProfileActivity.this, relationShip -> { + this.relationship = relationShip; + updateAccount(); + })); builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> { accountsVM.mute(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, target, true, 0) .observe(ProfileActivity.this, relationShip -> { diff --git a/app/src/main/java/app/fedilab/android/activities/SearchResultTabActivity.java b/app/src/main/java/app/fedilab/android/activities/SearchResultTabActivity.java index 5b27f224..2e6584a8 100644 --- a/app/src/main/java/app/fedilab/android/activities/SearchResultTabActivity.java +++ b/app/src/main/java/app/fedilab/android/activities/SearchResultTabActivity.java @@ -130,9 +130,10 @@ public class SearchResultTabActivity extends BaseBarActivity { search = query.trim(); ScreenSlidePagerAdapter mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager()); binding.searchViewpager.setAdapter(mPagerAdapter); - searchView.clearFocus(); setTitle(search); searchView.setIconified(true); + searchView.setQuery(search, false); + searchView.clearFocus(); binding.searchTabLayout.selectTab(initial); return false; } diff --git a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt index 955b615c..32edbad4 100644 --- a/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt +++ b/app/src/main/java/app/fedilab/android/activities/SettingsActivity.kt @@ -36,6 +36,7 @@ class SettingsActivity : BaseBarActivity() { val navController = findNavController(R.id.fragment_container) appBarConfiguration = AppBarConfiguration.Builder().build() setupActionBarWithNavController(navController, appBarConfiguration) + } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java index 9ece8182..7a2bd1f2 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Account.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Account.java @@ -85,7 +85,7 @@ public class Account implements Serializable { if (display_name == null || display_name.isEmpty()) { display_name = username; } - return SpannableHelper.convert(context, display_name, null, this, null, false, viewWeakReference); + return SpannableHelper.convert(context, display_name, null, this, null, false, false, viewWeakReference); } public synchronized Spannable getSpanDisplayName(Activity activity, WeakReference viewWeakReference) { @@ -96,11 +96,11 @@ public class Account implements Serializable { } public synchronized Spannable getSpanDisplayNameTitle(Context context, WeakReference viewWeakReference, String title) { - return SpannableHelper.convert(context, title, null, this, null, false, viewWeakReference); + return SpannableHelper.convert(context, title, null, this, null, false, false, viewWeakReference); } public synchronized Spannable getSpanNote(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, note, null, this, null, true, viewWeakReference); + return SpannableHelper.convert(context, note, null, this, null, true, true, viewWeakReference); } public static class AccountParams implements Serializable { diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java index b015313f..808ac6e5 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Announcement.java @@ -56,7 +56,7 @@ public class Announcement { public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, content, null, null, this, true, viewWeakReference); + return SpannableHelper.convert(context, content, null, null, this, true, false, viewWeakReference); } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Attachment.java b/app/src/main/java/app/fedilab/android/client/entities/api/Attachment.java index c4a2b9ab..f569a242 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Attachment.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Attachment.java @@ -51,6 +51,8 @@ public class Attachment implements Serializable { public String focus = null; public String translation = null; + public float measuredWidth = -1.f; + public static class Meta implements Serializable { @SerializedName("focus") public Focus focus; diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Field.java b/app/src/main/java/app/fedilab/android/client/entities/api/Field.java index 0fdbb3a6..af574ee3 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Field.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Field.java @@ -47,7 +47,7 @@ public class Field implements Serializable { if (verified_at != null && value != null) { value_span = new ForegroundColorSpan(ContextCompat.getColor(context, R.color.verified_text)); } - Spannable spannable = SpannableHelper.convert(context, value, null, account, null, true, viewWeakReference); + Spannable spannable = SpannableHelper.convert(context, value, null, account, null, true, true, viewWeakReference); if (value_span != null && spannable != null) { spannable.setSpan(value_span, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } @@ -57,7 +57,7 @@ public class Field implements Serializable { public synchronized Spannable getLabelSpan(Context context, Account account, WeakReference viewWeakReference) { - Spannable spannable = SpannableHelper.convert(context, name, null, account, null, true, viewWeakReference); + Spannable spannable = SpannableHelper.convert(context, name, null, account, null, true, true, viewWeakReference); if (name_span != null && spannable != null) { spannable.setSpan(name_span, 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java b/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java index 3bf9c479..cf0d1d8b 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Poll.java @@ -61,7 +61,7 @@ public class Poll implements Serializable { public transient Spannable span_title; public Spannable getSpanTitle(Context context, Status status, WeakReference viewWeakReference) { - span_title = SpannableHelper.convert(context, title, status, null, null, false, viewWeakReference); + span_title = SpannableHelper.convert(context, title, status, null, null, false, false, viewWeakReference); return span_title; } } diff --git a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java index e3c75305..7c39f487 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/api/Status.java +++ b/app/src/main/java/app/fedilab/android/client/entities/api/Status.java @@ -115,6 +115,10 @@ public class Status implements Serializable, Cloneable { public transient boolean submitted = false; public transient boolean spoilerChecked = false; public Filter filteredByApp; + public transient Spannable contentSpan; + public transient Spannable contentSpoilerSpan; + public transient Spannable contentTranslateSpan; + @Override public boolean equals(@Nullable Object obj) { boolean same = false; @@ -124,17 +128,29 @@ public class Status implements Serializable, Cloneable { return same; } - public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, content, this, null, null, true, viewWeakReference); + public synchronized Spannable getSpanContent(Context context, WeakReference viewWeakReference, Callback callback) { + if (contentSpan == null) { + contentSpan = SpannableHelper.convert(context, content, this, null, null, true, false, viewWeakReference, callback); + } + return contentSpan; } - - public synchronized Spannable getSpanSpoiler(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, spoiler_text, this, null, null, true, viewWeakReference); + public synchronized Spannable getSpanSpoiler(Context context, WeakReference viewWeakReference, Callback callback) { + if (contentSpoilerSpan == null) { + contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, true, false, viewWeakReference, callback); + } + return contentSpoilerSpan; } - public synchronized Spannable getSpanTranslate(Context context, WeakReference viewWeakReference) { - return SpannableHelper.convert(context, translationContent, this, null, null, true, viewWeakReference); + public synchronized Spannable getSpanTranslate(Context context, WeakReference viewWeakReference, Callback callback) { + if (contentTranslateSpan == null) { + contentTranslateSpan = SpannableHelper.convert(context, translationContent, this, null, null, true, false, viewWeakReference, callback); + } + return contentTranslateSpan; + } + + public interface Callback { + void emojiFetched(); } @NonNull diff --git a/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java b/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java index 10835111..f121afc1 100644 --- a/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java +++ b/app/src/main/java/app/fedilab/android/helper/CustomEmoji.java @@ -6,6 +6,7 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; +import android.text.SpannableStringBuilder; import android.text.style.ReplacementSpan; import android.view.View; @@ -13,26 +14,53 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; +import com.bumptech.glide.Glide; import com.bumptech.glide.request.target.CustomTarget; import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.transition.Transition; import java.lang.ref.WeakReference; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import app.fedilab.android.R; +import app.fedilab.android.client.entities.api.Emoji; +import app.fedilab.android.client.entities.api.Status; public class CustomEmoji extends ReplacementSpan { private final float scale; private final WeakReference viewWeakReference; private Drawable imageDrawable; - + private boolean callbackCalled; CustomEmoji(WeakReference viewWeakReference) { Context mContext = viewWeakReference.get().getContext(); this.viewWeakReference = viewWeakReference; SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(mContext); scale = sharedpreferences.getFloat(mContext.getString(R.string.SET_FONT_SCALE), 1.1f); + callbackCalled = false; + } + + public SpannableStringBuilder makeEmoji(SpannableStringBuilder content, List emojiList, boolean animate, Status.Callback callback) { + if (emojiList != null && emojiList.size() > 0) { + int count = 1; + for (Emoji emoji : emojiList) { + Matcher matcher = Pattern.compile(":" + emoji.shortcode + ":", Pattern.LITERAL) + .matcher(content); + while (matcher.find()) { + CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(viewWeakReference.get())); + content.setSpan(customEmoji, matcher.start(), matcher.end(), 0); + Glide.with(viewWeakReference.get()) + .asDrawable() + .load(animate ? emoji.url : emoji.static_url) + .into(customEmoji.getTarget(animate, count == emojiList.size() && !callbackCalled ? callback : null)); + } + count++; + } + } + return content; } @Override @@ -61,7 +89,7 @@ public class CustomEmoji extends ReplacementSpan { } } - public Target getTarget(boolean animate) { + public Target getTarget(boolean animate, Status.Callback callback) { return new CustomTarget() { @Override public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { @@ -97,6 +125,10 @@ public class CustomEmoji extends ReplacementSpan { if (view != null) { view.invalidate(); } + if (callback != null && !callbackCalled) { + callbackCalled = true; + callback.emojiFetched(); + } } @Override diff --git a/app/src/main/java/app/fedilab/android/helper/Helper.java b/app/src/main/java/app/fedilab/android/helper/Helper.java index c8af7bef..8b10a874 100644 --- a/app/src/main/java/app/fedilab/android/helper/Helper.java +++ b/app/src/main/java/app/fedilab/android/helper/Helper.java @@ -323,7 +323,7 @@ public class Helper { Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);*/ - public static final Pattern hashtagPattern = Pattern.compile("(#[\\w_A-zÀ-ÿ]+)"); + public static final Pattern hashtagPattern = Pattern.compile("(^|\\s+|[.,;?!-]+)(#[\\w_A-zÀ-ÿ]+)"); public static final Pattern groupPattern = Pattern.compile("(![\\w_]+)"); public static final Pattern mentionPattern = Pattern.compile("(@[\\w_.-]+[\\w])"); public static final Pattern mentionLongPattern = Pattern.compile("(@[\\w_.-]+@[a-zA-Z0-9][a-zA-Z0-9.-]{1,61}[a-zA-Z0-9](?:\\.[a-zA-Z]{2,})+)"); @@ -1918,6 +1918,8 @@ public class Helper { return R.style.SolarizedAlertDialog; } else if (R.style.BlackAppThemeBar == currentThemeId || R.style.BlackAppTheme == currentThemeId) { return R.style.BlackAlertDialog; + } else if (R.style.DraculaAppThemeBar == currentThemeId || R.style.DraculaAppTheme == currentThemeId) { + return R.style.DraculaAlertDialog; } return R.style.AppTheme; } diff --git a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java index 455614b3..9508f750 100644 --- a/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/SpannableHelper.java @@ -24,6 +24,7 @@ import android.content.ClipboardManager; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.net.Uri; import android.os.Build; import android.os.Bundle; @@ -40,7 +41,6 @@ import android.text.style.URLSpan; import android.util.Patterns; import android.view.LayoutInflater; import android.view.View; -import android.webkit.URLUtil; import android.widget.Toast; import androidx.annotation.NonNull; @@ -91,10 +91,38 @@ public class SpannableHelper { public static Spannable convert(Context context, String text, Status status, Account account, Announcement announcement, - boolean convertHtml, - WeakReference viewWeakReference) { + boolean convertHtml, boolean forceMentions, WeakReference viewWeakReference) { + return convert(context, text, status, account, announcement, convertHtml, forceMentions, viewWeakReference, null); + } + private static int linkColor; + + public static Spannable convert(Context context, String text, + Status status, Account account, Announcement announcement, + boolean convertHtml, + boolean forceMentions, + WeakReference viewWeakReference, Status.Callback callback) { + + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + boolean customLight = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOMIZE_LIGHT_COLORS), false); + boolean customDark = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOMIZE_DARK_COLORS), false); + int link_color; + if (currentNightMode == Configuration.UI_MODE_NIGHT_NO && customLight) { + link_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_LINK), -1); + if (link_color != -1) { + linkColor = link_color; + } + } else if (currentNightMode == Configuration.UI_MODE_NIGHT_YES && customDark) { + link_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_LINK), -1); + if (link_color != -1) { + linkColor = link_color; + } + } else { + linkColor = ThemeHelper.getAttColor(context, R.attr.linkColor); + } + SpannableString initialContent; if (text == null) { return null; @@ -123,6 +151,7 @@ public class SpannableHelper { } else if (announcement != null) { emojiList = announcement.emojis; } + //UrlDetails will contain links having a text different from the url HashMap urlDetails = new HashMap<>(); if (convertHtml) { Matcher matcherALink = Helper.aLink.matcher(text); @@ -134,7 +163,7 @@ public class SpannableHelper { if (urlText != null && urlText.startsWith(">")) { urlText = urlText.substring(1); } - if (url != null && urlText != null && !url.equals(urlText) && !urlText.contains(" 0) { - for (Emoji emoji : emojiList) { - Matcher matcher = Pattern.compile(":" + emoji.shortcode + ":", Pattern.LITERAL) - .matcher(content); - while (matcher.find()) { - CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view)); - content.setSpan(customEmoji, matcher.start(), matcher.end(), 0); - Glide.with(view) - .asDrawable() - .load(animate ? emoji.url : emoji.static_url) - .into(customEmoji.getTarget(animate)); - } - } - } + CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view)); + content = customEmoji.makeEmoji(content, emojiList, animate, callback); if (imagesToReplace.size() > 0) { for (Map.Entry entry : imagesToReplace.entrySet()) { @@ -183,12 +199,11 @@ public class SpannableHelper { Matcher matcher = Pattern.compile(key, Pattern.LITERAL) .matcher(content); while (matcher.find()) { - CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view)); content.setSpan(customEmoji, matcher.start(), matcher.end(), 0); Glide.with(view) .asDrawable() .load(url) - .into(customEmoji.getTarget(animate)); + .into(customEmoji.getTarget(animate, null)); } } @@ -216,16 +231,15 @@ public class SpannableHelper { final String url = content.toString().substring(matchStart, matchEnd); + if (urlDetails.containsKey(url)) { + continue; + } String newURL = Helper.transformURL(context, url); //If URL has been transformed if (newURL.compareTo(url) != 0) { content.replace(matchStart, matchEnd, newURL); offSetTruncate -= (newURL.length() - url.length()); matchEnd = matchStart + newURL.length(); - //The transformed URL was in the list of URLs having a different names - if (urlDetails.containsKey(url)) { - urlDetails.put(newURL, urlDetails.get(url)); - } } //Truncate URL if needed @@ -237,14 +251,7 @@ public class SpannableHelper { content.replace(matchStart, matchEnd, urlText); matchEnd = matchStart + 31; offSetTruncate += (newURL.length() - urlText.length()); - } /*else if (urlDetails.containsKey(urlText) && urlDetails.get(urlText) != null) { - urlText = urlDetails.get(urlText); - if (urlText != null) { - content.replace(matchStart, matchEnd, urlText); - matchEnd = matchStart + urlText.length(); - offSetTruncate += (newURL.length() - urlText.length()); - } - }*/ + } if (matchEnd <= content.length() && matchEnd >= matchStart) { @@ -336,7 +343,7 @@ public class SpannableHelper { } } httpsURLConnection.getInputStream().close(); - if (redirect != null && finalURl1 != null && redirect.compareTo(finalURl1) != 0) { + if (redirect != null && redirect.compareTo(finalURl1) != 0) { URL redirectURL = new URL(redirect); String host = redirectURL.getHost(); String protocol = redirectURL.getProtocol(); @@ -446,6 +453,12 @@ public class SpannableHelper { } + @Override + public void updateDrawState(@NonNull TextPaint ds) { + super.updateDrawState(ds); + ds.setColor(linkColor); + } + }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } } @@ -455,7 +468,7 @@ public class SpannableHelper { for (Map.Entry entry : urlDetails.entrySet()) { String value = entry.getValue(); - if (value.startsWith("@") || value.startsWith("#") || !URLUtil.isValidUrl(value)) { + if (value.startsWith("@") || value.startsWith("#")) { continue; } SpannableString contentUrl; @@ -464,7 +477,7 @@ public class SpannableHelper { else contentUrl = new SpannableString(Html.fromHtml(value)); - Pattern word = Pattern.compile(contentUrl.toString()); + Pattern word = Pattern.compile(Pattern.quote(contentUrl.toString())); Matcher matcherLink = word.matcher(content); while (matcherLink.find()) { String url = entry.getKey(); @@ -668,6 +681,7 @@ public class SpannableHelper { public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); + ds.setColor(linkColor); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } @@ -701,6 +715,7 @@ public class SpannableHelper { public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); + ds.setColor(linkColor); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } @@ -737,21 +752,22 @@ public class SpannableHelper { public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); + ds.setColor(linkColor); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); } } } - private static void interaction(Context context, Spannable content, Status status, List mentions) { + private static void interaction(Context context, Spannable content, Status status, List mentions, boolean forceMentions) { // --- For all patterns defined in Helper class --- for (Map.Entry entry : Helper.patternHashMap.entrySet()) { Helper.PatternType patternType = entry.getKey(); Pattern pattern = entry.getValue(); Matcher matcher = pattern.matcher(content); - if (pattern == Helper.mentionPattern && mentions == null) { + if (pattern == Helper.mentionPattern && mentions == null && !forceMentions) { continue; - } else if (pattern == Helper.mentionLongPattern && mentions == null) { + } else if (pattern == Helper.mentionLongPattern && mentions == null && !forceMentions) { continue; } @@ -884,6 +900,7 @@ public class SpannableHelper { public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); ds.setUnderlineText(false); + ds.setColor(linkColor); } }, matchStart, matchEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); @@ -1031,6 +1048,8 @@ public class SpannableHelper { @Override public void updateDrawState(@NonNull TextPaint ds) { super.updateDrawState(ds); + ds.setUnderlineText(false); + ds.setColor(linkColor); } }, startPosition, endPosition, @@ -1066,7 +1085,7 @@ public class SpannableHelper { Glide.with(viewWeakReference.get()) .asDrawable() .load(animate ? emoji.url : emoji.static_url) - .into(customEmoji.getTarget(animate)); + .into(customEmoji.getTarget(animate, null)); } } } diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java index 7fdfb581..2b0448de 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/AccountAdapter.java @@ -68,6 +68,11 @@ public class AccountAdapter extends RecyclerView.Adapter { Intent intent = new Intent(context, ProfileActivity.class); Bundle b = new Bundle(); @@ -78,6 +83,8 @@ public class AccountAdapter extends RecyclerView.Adapter 0) { ReactionAdapter reactionAdapter = new ReactionAdapter(announcement.id, announcement.reactions); holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java index 32326720..c4efd535 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ComposeAdapter.java @@ -725,6 +725,13 @@ public class ComposeAdapter extends RecyclerView.Adapter(holder.binding.statusContent)), + new WeakReference<>(holder.binding.statusContent), null), TextView.BufferType.SPANNABLE); MastodonHelper.loadPPMastodon(holder.binding.avatar, status.account); if (status.account != null) { @@ -1122,7 +1129,7 @@ public class ComposeAdapter extends RecyclerView.Adapter(holder.binding.spoiler)), + new WeakReference<>(holder.binding.spoiler), null), TextView.BufferType.SPANNABLE); } else { holder.binding.spoiler.setVisibility(View.GONE); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java index ed5c8b61..c98b9062 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/ConversationAdapter.java @@ -19,6 +19,7 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.os.Handler; import android.os.Looper; import android.view.LayoutInflater; @@ -83,14 +84,56 @@ public class ConversationAdapter extends RecyclerView.Adapter(holder.binding.spoiler)), + new WeakReference<>(holder.binding.spoiler), () -> notifyItemChanged(holder.getBindingAdapterPosition())), TextView.BufferType.SPANNABLE); } else { holder.binding.spoiler.setVisibility(View.GONE); @@ -161,7 +204,7 @@ public class ConversationAdapter extends RecyclerView.Adapter(holder.binding.statusContent)), + new WeakReference<>(holder.binding.statusContent), () -> notifyItemChanged(holder.getBindingAdapterPosition())), TextView.BufferType.SPANNABLE); //--- DATE --- holder.binding.lastMessageDate.setText(Helper.dateDiff(context, conversation.last_status.created_at)); @@ -198,6 +241,8 @@ public class ConversationAdapter extends RecyclerView.Adapter. */ import android.content.Context; +import android.content.SharedPreferences; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import java.util.List; @@ -61,6 +64,13 @@ public class DomainBlockAdapter extends RecyclerView.Adapter { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java index a88c24ad..82a5703d 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/InstanceRegAdapter.java @@ -16,11 +16,13 @@ package app.fedilab.android.ui.drawer; import android.content.Context; +import android.content.SharedPreferences; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; @@ -46,6 +48,11 @@ public class InstanceRegAdapter extends RecyclerView.Adapter notificationList) { this.notificationList = notificationList; @@ -120,6 +122,13 @@ public class NotificationAdapter extends RecyclerView.Adapter { notification.filteredByApp = null; @@ -226,6 +286,11 @@ public class NotificationAdapter extends RecyclerView.Adapter 0) { holderStatus.bindingNotification.status.mediaContainer.setVisibility(View.VISIBLE); @@ -362,6 +443,7 @@ public class NotificationAdapter extends RecyclerView.Adapter public FetchMoreCallBack fetchMoreCallBack; private Context context; + private RecyclerView mRecyclerView; + public StatusAdapter(List statuses, Timeline.TimeLineEnum timelineType, boolean minified, boolean canBeFederated, boolean checkRemotely) { this.statusList = statuses; this.timelineType = timelineType; @@ -173,6 +177,18 @@ public class StatusAdapter extends RecyclerView.Adapter this.checkRemotely = checkRemotely; } + public static int getStatusPosition(List timelineStatuses, Status status) { + int position = 0; + if (timelineStatuses != null && status != null) { + for (Status _s : timelineStatuses) { + if (_s.id.compareTo(status.id) == 0) { + return position; + } + position++; + } + } + return -1; + } private static boolean isVisible(Timeline.TimeLineEnum timelineType, Status status) { if (timelineType == Timeline.TimeLineEnum.HOME && !show_boosts && status.reblog != null) { @@ -355,6 +371,7 @@ public class StatusAdapter extends RecyclerView.Adapter StatusesVM statusesVM, SearchVM searchVM, StatusViewHolder holder, + RecyclerView recyclerView, RecyclerView.Adapter adapter, List statusList, Status status, @@ -372,14 +389,12 @@ public class StatusAdapter extends RecyclerView.Adapter boolean expand_cw = sharedpreferences.getBoolean(context.getString(R.string.SET_EXPAND_CW), false); - boolean expand_media = sharedpreferences.getBoolean(context.getString(R.string.SET_EXPAND_MEDIA), false); boolean display_card = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_CARD), false); boolean share_details = sharedpreferences.getBoolean(context.getString(R.string.SET_SHARE_DETAILS), true); boolean confirmFav = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION_FAV), false); boolean confirmBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION), true); boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false); boolean displayBookmark = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_BOOKMARK), true); - boolean long_press_media = sharedpreferences.getBoolean(context.getString(R.string.SET_LONG_PRESS_STORE_MEDIA), false); boolean displayCounters = sharedpreferences.getBoolean(context.getString(R.string.SET_DISPLAY_COUNTER_FAV_BOOST), false); String loadMediaType = sharedpreferences.getString(context.getString(R.string.SET_LOAD_MEDIA_TYPE), "ALWAYS"); @@ -506,16 +521,19 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.actionButtonFavorite.pressOnTouch(false); holder.binding.actionButtonBoost.pressOnTouch(false); holder.binding.actionButtonBookmark.pressOnTouch(false); - holder.binding.actionButtonFavorite.setActiveImage(R.drawable.ic_baseline_star_24); - holder.binding.actionButtonFavorite.setInactiveImage(R.drawable.ic_star_outline); - holder.binding.actionButtonBookmark.setInactiveImage(R.drawable.ic_baseline_bookmark_border_24); + holder.binding.actionButtonFavorite.setActiveImage(R.drawable.ic_round_star_24); + holder.binding.actionButtonFavorite.setInactiveImage(R.drawable.ic_round_star_border_24); + holder.binding.actionButtonBookmark.setActiveImage(R.drawable.ic_round_bookmark_24); + holder.binding.actionButtonBookmark.setInactiveImage(R.drawable.ic_round_bookmark_border_24); + holder.binding.actionButtonBoost.setActiveImage(R.drawable.ic_round_repeat_24); + holder.binding.actionButtonBoost.setInactiveImage(R.drawable.ic_round_repeat_24); holder.binding.actionButtonFavorite.setDisableCircle(true); holder.binding.actionButtonBoost.setDisableCircle(true); holder.binding.actionButtonBookmark.setDisableCircle(true); holder.binding.actionButtonFavorite.setActiveImageTint(R.color.marked_icon); holder.binding.actionButtonBoost.setActiveImageTint(R.color.boost_icon); holder.binding.actionButtonBookmark.setActiveImageTint(R.color.marked_icon); - + applyColor(context, holder); if (status.pinned) { holder.binding.statusPinned.setVisibility(View.VISIBLE); @@ -865,13 +883,13 @@ public class StatusAdapter extends RecyclerView.Adapter } //Button sizes depending of the defined scale float normalSize = Helper.convertDpToPixel(28, context); - float normalSize2 = Helper.convertDpToPixel(24, context); + holder.binding.actionButtonReply.getLayoutParams().width = (int) (normalSize * scaleIcon); holder.binding.actionButtonReply.getLayoutParams().height = (int) (normalSize * scaleIcon); holder.binding.actionButtonReply.requestLayout(); holder.binding.actionButtonBoost.setImageSize((int) (normalSize * scaleIcon)); holder.binding.actionButtonFavorite.setImageSize((int) (normalSize * scaleIcon)); - holder.binding.actionButtonBookmark.setImageSize((int) (normalSize2 * scaleIcon)); + holder.binding.actionButtonBookmark.setImageSize((int) (normalSize * scaleIcon)); holder.binding.statusAddCustomEmoji.getLayoutParams().width = (int) (normalSize * scaleIcon); holder.binding.statusAddCustomEmoji.getLayoutParams().height = (int) (normalSize * scaleIcon); @@ -986,7 +1004,7 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.spoiler.setVisibility(View.VISIBLE); holder.binding.spoiler.setText( statusToDeal.getSpanSpoiler(context, - new WeakReference<>(holder.binding.spoiler)), + new WeakReference<>(holder.binding.spoiler), () -> recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition()))), TextView.BufferType.SPANNABLE); statusToDeal.isExpended = true; statusToDeal.isMediaDisplayed = true; @@ -1001,7 +1019,7 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.spoiler.setText( statusToDeal.getSpanSpoiler(context, - new WeakReference<>(holder.binding.spoiler)), + new WeakReference<>(holder.binding.spoiler), () -> recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition()))), TextView.BufferType.SPANNABLE); } if (statusToDeal.isExpended) { @@ -1049,7 +1067,9 @@ public class StatusAdapter extends RecyclerView.Adapter //--- MAIN CONTENT --- holder.binding.statusContent.setText( statusToDeal.getSpanContent(context, - new WeakReference<>(holder.binding.statusContent)), + new WeakReference<>(holder.binding.statusContent), () -> { + recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition())); + }), TextView.BufferType.SPANNABLE); if (truncate_toots_size > 0) { holder.binding.statusContent.setMaxLines(truncate_toots_size); @@ -1085,7 +1105,9 @@ public class StatusAdapter extends RecyclerView.Adapter holder.binding.containerTrans.setVisibility(View.VISIBLE); holder.binding.statusContentTranslated.setText( statusToDeal.getSpanTranslate(context, - new WeakReference<>(holder.binding.statusContentTranslated)), + new WeakReference<>(holder.binding.statusContentTranslated), () -> { + recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition())); + }), TextView.BufferType.SPANNABLE); } else { holder.binding.containerTrans.setVisibility(View.GONE); @@ -1106,234 +1128,70 @@ public class StatusAdapter extends RecyclerView.Adapter if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0) { holder.binding.attachmentsList.removeAllViews(); holder.binding.mediaContainer.removeAllViews(); - //If only one attachment - if (statusToDeal.media_attachments.size() == 1) { - if ((loadMediaType.equals("ASK") || (loadMediaType.equals("WIFI") && !TimelineHelper.isOnWIFI(context))) && !statusToDeal.canLoadMedia) { - holder.binding.mediaContainer.setVisibility(View.GONE); - holder.binding.displayMedia.setVisibility(View.VISIBLE); - holder.binding.displayMedia.setOnClickListener(v -> { - statusToDeal.canLoadMedia = true; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - }); - } else { - holder.binding.mediaContainer.setVisibility(View.VISIBLE); - holder.binding.displayMedia.setVisibility(View.GONE); - LayoutMediaBinding layoutMediaBinding = LayoutMediaBinding.inflate(LayoutInflater.from(context), holder.binding.attachmentsList, false); - LinearLayout.LayoutParams lp; + if ((loadMediaType.equals("ASK") || (loadMediaType.equals("WIFI") && !TimelineHelper.isOnWIFI(context))) && !statusToDeal.canLoadMedia) { + holder.binding.mediaContainer.setVisibility(View.GONE); + holder.binding.displayMedia.setVisibility(View.VISIBLE); + holder.binding.displayMedia.setOnClickListener(v -> { + statusToDeal.canLoadMedia = true; + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); + }); + } else { + int mediaPosition = 1; + boolean singleMedia = statusToDeal.media_attachments.size() == 1; + for (Attachment attachment : statusToDeal.media_attachments) { + LayoutMediaBinding layoutMediaBinding = LayoutMediaBinding.inflate(LayoutInflater.from(context)); if (fullAttachement) { - lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - layoutMediaBinding.media.setScaleType(ImageView.ScaleType.FIT_CENTER); - } else { - lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) Helper.convertDpToPixel(200, context)); - layoutMediaBinding.media.setScaleType(ImageView.ScaleType.CENTER_CROP); - } - if (statusToDeal.sensitive) { - Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, ThemeHelper.getAttColor(context, R.attr.colorError)); - } else { - Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, R.color.white); - } - layoutMediaBinding.media.setLayoutParams(lp); - layoutMediaBinding.media.setOnClickListener(v -> { - if (statusToDeal.isMediaObfuscated && mediaObfuscated(statusToDeal) && !expand_media) { - statusToDeal.isMediaObfuscated = false; - int position = holder.getBindingAdapterPosition(); - adapter.notifyItemChanged(position); - final int timeout = sharedpreferences.getInt(context.getString(R.string.SET_NSFW_TIMEOUT), 5); + float ratio = 1.0f; + float mediaH = -1.0f; - if (timeout > 0) { - new CountDownTimer((timeout * 1000L), 1000) { - public void onTick(long millisUntilFinished) { - } - - public void onFinish() { - status.isMediaObfuscated = true; - adapter.notifyItemChanged(position); - } - }.start(); + if (attachment.measuredWidth > 0) { + if (attachment.meta != null && attachment.meta.small != null) { + float viewWidth = attachment.measuredWidth; + mediaH = attachment.meta.small.height; + float mediaW = attachment.meta.small.width; + if (mediaW != 0) { + ratio = viewWidth / mediaW; + } } - return; + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, mediaH, ratio, statusToDeal, attachment, singleMedia); + } else { + int finalMediaPosition = mediaPosition; + layoutMediaBinding.media.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + layoutMediaBinding.media.getViewTreeObserver().removeOnGlobalLayoutListener(this); + attachment.measuredWidth = layoutMediaBinding.media.getWidth(); + float ratio = 1.0f; + float mediaH = -1.0f; + if (attachment.meta != null && attachment.meta.small != null) { + float viewWidth = attachment.measuredWidth; + mediaH = attachment.meta.small.height; + float mediaW = attachment.meta.small.width; + if (mediaW != 0) { + ratio = viewWidth / mediaW; + } + } + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, finalMediaPosition, mediaH, ratio, statusToDeal, attachment, singleMedia); + } + }); } - Intent mediaIntent = new Intent(context, MediaActivity.class); - Bundle b = new Bundle(); - b.putInt(Helper.ARG_MEDIA_POSITION, 1); - b.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments)); - mediaIntent.putExtras(b); - ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation((Activity) context, layoutMediaBinding.media, statusToDeal.media_attachments.get(0).url); - // start the new activity - context.startActivity(mediaIntent, options.toBundle()); - }); - if (statusToDeal.media_attachments.get(0).type != null && (statusToDeal.media_attachments.get(0).type.equalsIgnoreCase("video") || statusToDeal.media_attachments.get(0).type.equalsIgnoreCase("gifv"))) { - layoutMediaBinding.playVideo.setVisibility(View.VISIBLE); } else { - layoutMediaBinding.playVideo.setVisibility(View.GONE); + loadAndAddAttachment(context, layoutMediaBinding, holder, adapter, mediaPosition, -1.f, -1.f, statusToDeal, attachment, singleMedia); } - if (statusToDeal.media_attachments.get(0).type != null && statusToDeal.media_attachments.get(0).type.equalsIgnoreCase("audio")) { - layoutMediaBinding.playMusic.setVisibility(View.VISIBLE); + mediaPosition++; + if (fullAttachement || singleMedia) { + holder.binding.mediaContainer.addView(layoutMediaBinding.getRoot()); } else { - layoutMediaBinding.playMusic.setVisibility(View.GONE); + holder.binding.attachmentsList.addView(layoutMediaBinding.getRoot()); } - String finalUrl; - if (statusToDeal.media_attachments.get(0).url == null) { - finalUrl = statusToDeal.media_attachments.get(0).remote_url; - } else { - finalUrl = statusToDeal.media_attachments.get(0).url; - } - layoutMediaBinding.media.setOnLongClickListener(v -> { - if (long_press_media) { - MediaHelper.manageMove(context, finalUrl, false); - } - return true; - }); - - float focusX = 0.f; - float focusY = 0.f; - if (statusToDeal.media_attachments.get(0).meta != null && statusToDeal.media_attachments.get(0).meta.focus != null) { - focusX = statusToDeal.media_attachments.get(0).meta.focus.x; - focusY = statusToDeal.media_attachments.get(0).meta.focus.y; - } - if (statusToDeal.media_attachments.get(0).description != null && !statusToDeal.media_attachments.get(0).description.isEmpty()) { - layoutMediaBinding.viewDescription.setVisibility(View.VISIBLE); - } else { - layoutMediaBinding.viewDescription.setVisibility(View.GONE); - } - if (!mediaObfuscated(statusToDeal) || expand_media) { - layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24); - RequestBuilder requestBuilder = Glide.with(layoutMediaBinding.media.getContext()) - .load(statusToDeal.media_attachments.get(0).preview_url); - if (!fullAttachement) { - requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY))); - } - requestBuilder.into(layoutMediaBinding.media); - } else { - layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24); - Glide.with(layoutMediaBinding.media.getContext()) - .load(statusToDeal.media_attachments.get(0).preview_url) - .apply(new RequestOptions().transform(new BlurTransformation(50, 3))) - // .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context)))) - .into(layoutMediaBinding.media); - } - layoutMediaBinding.viewHide.setOnClickListener(v -> { - statusToDeal.sensitive = !statusToDeal.sensitive; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - }); - holder.binding.mediaContainer.addView(layoutMediaBinding.getRoot()); + } + if (!fullAttachement && !singleMedia) { + holder.binding.mediaContainer.setVisibility(View.GONE); + holder.binding.attachmentsListContainer.setVisibility(View.VISIBLE); + } else { holder.binding.mediaContainer.setVisibility(View.VISIBLE); holder.binding.attachmentsListContainer.setVisibility(View.GONE); } - } else { //Several media - if ((loadMediaType.equals("ASK") || (loadMediaType.equals("WIFI") && !TimelineHelper.isOnWIFI(context))) && !statusToDeal.canLoadMedia) { - holder.binding.mediaContainer.setVisibility(View.GONE); - holder.binding.displayMedia.setVisibility(View.VISIBLE); - holder.binding.displayMedia.setOnClickListener(v -> { - statusToDeal.canLoadMedia = true; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - }); - } else { - int mediaPosition = 1; - for (Attachment attachment : statusToDeal.media_attachments) { - LayoutMediaBinding layoutMediaBinding = LayoutMediaBinding.inflate(LayoutInflater.from(context), holder.binding.attachmentsList, false); - LinearLayout.LayoutParams lp; - float focusX = 0.f; - float focusY = 0.f; - if (statusToDeal.media_attachments.get(0).meta != null && statusToDeal.media_attachments.get(0).meta.focus != null) { - focusX = statusToDeal.media_attachments.get(0).meta.focus.x; - focusY = statusToDeal.media_attachments.get(0).meta.focus.y; - } - layoutMediaBinding.count.setVisibility(View.VISIBLE); - if (!fullAttachement) { - layoutMediaBinding.count.setText(String.format(Locale.getDefault(), "%d/%d", mediaPosition, statusToDeal.media_attachments.size())); - } - String finalUrl; - if (attachment.url == null) { - finalUrl = attachment.remote_url; - } else { - finalUrl = attachment.url; - } - layoutMediaBinding.media.setOnLongClickListener(v -> { - if (long_press_media) { - MediaHelper.manageMove(context, finalUrl, false); - } - return true; - }); - if (fullAttachement) { - lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - layoutMediaBinding.media.setScaleType(ImageView.ScaleType.FIT_CENTER); - } else { - lp = new LinearLayout.LayoutParams((int) Helper.convertDpToPixel(200, context), (int) Helper.convertDpToPixel(200, context)); - layoutMediaBinding.media.setScaleType(ImageView.ScaleType.CENTER_CROP); - } - if (attachment.type != null && (attachment.type.equalsIgnoreCase("video") || attachment.type.equalsIgnoreCase("gifv"))) { - layoutMediaBinding.playVideo.setVisibility(View.VISIBLE); - } else { - layoutMediaBinding.playVideo.setVisibility(View.GONE); - } - if (attachment.type != null && attachment.type.equalsIgnoreCase("audio")) { - layoutMediaBinding.playMusic.setVisibility(View.VISIBLE); - } else { - layoutMediaBinding.playMusic.setVisibility(View.GONE); - } - if (attachment.description != null && !attachment.description.isEmpty()) { - layoutMediaBinding.viewDescription.setVisibility(View.VISIBLE); - } else { - layoutMediaBinding.viewDescription.setVisibility(View.GONE); - } - if (!mediaObfuscated(statusToDeal) || expand_media) { - layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24); - RequestBuilder requestBuilder = Glide.with(layoutMediaBinding.media.getContext()) - .load(attachment.preview_url); - if (!fullAttachement) { - requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY))); - } - requestBuilder.into(layoutMediaBinding.media); - } else { - layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24); - Glide.with(layoutMediaBinding.media.getContext()) - .load(attachment.preview_url) - .apply(new RequestOptions().transform(new BlurTransformation(50, 3))) - // .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context)))) - .into(layoutMediaBinding.media); - } - if (statusToDeal.sensitive) { - Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, ThemeHelper.getAttColor(context, R.attr.colorError)); - } else { - Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, R.color.white); - } - layoutMediaBinding.media.setLayoutParams(lp); - int finalMediaPosition = mediaPosition; - layoutMediaBinding.media.setOnClickListener(v -> { - Intent mediaIntent = new Intent(context, MediaActivity.class); - Bundle b = new Bundle(); - b.putInt(Helper.ARG_MEDIA_POSITION, finalMediaPosition); - b.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments)); - mediaIntent.putExtras(b); - ActivityOptionsCompat options = ActivityOptionsCompat - .makeSceneTransitionAnimation((Activity) context, layoutMediaBinding.media, statusToDeal.media_attachments.get(finalMediaPosition - 1).url); - // start the new activity - context.startActivity(mediaIntent, options.toBundle()); - }); - layoutMediaBinding.viewHide.setOnClickListener(v -> { - statusToDeal.sensitive = !statusToDeal.sensitive; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - }); - if (fullAttachement) { - layoutMediaBinding.getRoot().setPadding(0, 0, 0, 10); - holder.binding.mediaContainer.addView(layoutMediaBinding.getRoot()); - } else { - layoutMediaBinding.getRoot().setPadding(0, 0, 10, 0); - holder.binding.attachmentsList.addView(layoutMediaBinding.getRoot()); - } - - mediaPosition++; - } - if (!fullAttachement) { - holder.binding.mediaContainer.setVisibility(View.GONE); - holder.binding.attachmentsListContainer.setVisibility(View.VISIBLE); - } else { - holder.binding.mediaContainer.setVisibility(View.VISIBLE); - holder.binding.attachmentsListContainer.setVisibility(View.GONE); - } - } } } else { holder.binding.displayMedia.setVisibility(View.GONE); @@ -2012,21 +1870,34 @@ public class StatusAdapter extends RecyclerView.Adapter } if (status.isFetchMore && fetchMoreCallBack != null) { - holder.binding.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE); - holder.binding.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> { + DrawerFetchMoreBinding drawerFetchMoreBinding = DrawerFetchMoreBinding.inflate(LayoutInflater.from(context)); + if (status.positionFetchMore == Status.PositionFetchMore.BOTTOM) { + holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE); + holder.binding.fetchMoreContainerTop.setVisibility(View.VISIBLE); + holder.binding.fetchMoreContainerTop.removeAllViews(); + holder.binding.fetchMoreContainerTop.addView(drawerFetchMoreBinding.getRoot()); + } else { + holder.binding.fetchMoreContainerBottom.setVisibility(View.VISIBLE); + holder.binding.fetchMoreContainerTop.setVisibility(View.GONE); + holder.binding.fetchMoreContainerBottom.removeAllViews(); + holder.binding.fetchMoreContainerBottom.addView(drawerFetchMoreBinding.getRoot()); + } + drawerFetchMoreBinding.fetchMoreMin.setOnClickListener(v -> { status.isFetchMore = false; - adapter.notifyItemChanged(holder.getBindingAdapterPosition()); - if (holder.getBindingAdapterPosition() < statusList.size() - 1) { + int position = holder.getBindingAdapterPosition(); + int position2 = getStatusPosition(statusList, status); + adapter.notifyItemChanged(position); + if (position < statusList.size() - 1) { String fromId; if (status.positionFetchMore == Status.PositionFetchMore.TOP) { - fromId = statusList.get(holder.getBindingAdapterPosition() + 1).id; + fromId = statusList.get(position + 1).id; } else { fromId = status.id; } fetchMoreCallBack.onClickMinId(fromId, status); } }); - holder.binding.layoutFetchMore.fetchMoreMax.setOnClickListener(v -> { + drawerFetchMoreBinding.fetchMoreMax.setOnClickListener(v -> { //We hide the button status.isFetchMore = false; String fromId; @@ -2039,11 +1910,153 @@ public class StatusAdapter extends RecyclerView.Adapter adapter.notifyItemChanged(holder.getBindingAdapterPosition()); }); } else { - holder.binding.layoutFetchMore.fetchMoreContainer.setVisibility(View.GONE); + holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE); + holder.binding.fetchMoreContainerTop.setVisibility(View.GONE); } } + + private static void loadAndAddAttachment(Context context, LayoutMediaBinding layoutMediaBinding, + StatusViewHolder holder, + RecyclerView.Adapter adapter, + int mediaPosition, float mediaH, float ratio, + Status statusToDeal, Attachment attachment, boolean singleImage) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + final int timeout = sharedpreferences.getInt(context.getString(R.string.SET_NSFW_TIMEOUT), 5); + boolean fullAttachement = sharedpreferences.getBoolean(context.getString(R.string.SET_FULL_PREVIEW), false); + boolean long_press_media = sharedpreferences.getBoolean(context.getString(R.string.SET_LONG_PRESS_STORE_MEDIA), false); + boolean expand_media = sharedpreferences.getBoolean(context.getString(R.string.SET_EXPAND_MEDIA), false); + + LinearLayout.LayoutParams lp; + if (fullAttachement && mediaH > 0) { + lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) (mediaH * ratio)); + layoutMediaBinding.media.setScaleType(ImageView.ScaleType.FIT_CENTER); + } else { + if (singleImage) { + lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, (int) Helper.convertDpToPixel(200, context)); + } else { + lp = new LinearLayout.LayoutParams((int) Helper.convertDpToPixel(200, context), (int) Helper.convertDpToPixel(200, context)); + } + layoutMediaBinding.media.setScaleType(ImageView.ScaleType.CENTER_CROP); + } + + + layoutMediaBinding.media.setLayoutParams(lp); + + float focusX = 0.f; + float focusY = 0.f; + if (statusToDeal.media_attachments.get(0).meta != null && statusToDeal.media_attachments.get(0).meta.focus != null) { + focusX = statusToDeal.media_attachments.get(0).meta.focus.x; + focusY = statusToDeal.media_attachments.get(0).meta.focus.y; + } + layoutMediaBinding.count.setVisibility(View.VISIBLE); + if (!fullAttachement && !singleImage) { + layoutMediaBinding.count.setText(String.format(Locale.getDefault(), "%d/%d", mediaPosition, statusToDeal.media_attachments.size())); + } + String finalUrl; + if (attachment.url == null) { + finalUrl = attachment.remote_url; + } else { + finalUrl = attachment.url; + } + layoutMediaBinding.media.setOnLongClickListener(v -> { + if (long_press_media) { + MediaHelper.manageMove(context, finalUrl, false); + } + return true; + }); + + if (attachment.type != null && (attachment.type.equalsIgnoreCase("video") || attachment.type.equalsIgnoreCase("gifv"))) { + layoutMediaBinding.playVideo.setVisibility(View.VISIBLE); + } else { + layoutMediaBinding.playVideo.setVisibility(View.GONE); + } + if (attachment.type != null && attachment.type.equalsIgnoreCase("audio")) { + layoutMediaBinding.playMusic.setVisibility(View.VISIBLE); + } else { + layoutMediaBinding.playMusic.setVisibility(View.GONE); + } + if (attachment.description != null && !attachment.description.isEmpty()) { + layoutMediaBinding.viewDescription.setVisibility(View.VISIBLE); + } else { + layoutMediaBinding.viewDescription.setVisibility(View.GONE); + } + + if (!mediaObfuscated(statusToDeal) || expand_media) { + layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_24); + RequestBuilder requestBuilder = Glide.with(layoutMediaBinding.media.getContext()) + .load(attachment.preview_url); + if (!fullAttachement) { + requestBuilder = requestBuilder.apply(new RequestOptions().transform(new GlideFocus(focusX, focusY))); + } else { + requestBuilder = requestBuilder.placeholder(R.color.transparent_grey); + requestBuilder = requestBuilder.fitCenter(); + } + requestBuilder.into(layoutMediaBinding.media); + } else { + layoutMediaBinding.viewHide.setImageResource(R.drawable.ic_baseline_visibility_off_24); + Glide.with(layoutMediaBinding.media.getContext()) + .load(attachment.preview_url) + .apply(new RequestOptions().transform(new BlurTransformation(50, 3))) + // .apply(new RequestOptions().transform(new CenterCrop(), new RoundedCorners((int) Helper.convertDpToPixel(3, context)))) + .into(layoutMediaBinding.media); + } + if (statusToDeal.sensitive) { + Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, ThemeHelper.getAttColor(context, R.attr.colorError)); + } else { + Helper.changeDrawableColor(context, layoutMediaBinding.viewHide, R.color.white); + } + + layoutMediaBinding.media.setOnClickListener(v -> { + if (statusToDeal.isMediaObfuscated && mediaObfuscated(statusToDeal) && !expand_media) { + statusToDeal.isMediaObfuscated = false; + int position = holder.getBindingAdapterPosition(); + adapter.notifyItemChanged(position); + + if (timeout > 0) { + new CountDownTimer((timeout * 1000L), 1000) { + public void onTick(long millisUntilFinished) { + } + + public void onFinish() { + statusToDeal.isMediaObfuscated = true; + adapter.notifyItemChanged(position); + } + }.start(); + } + return; + } + Intent mediaIntent = new Intent(context, MediaActivity.class); + Bundle b = new Bundle(); + b.putInt(Helper.ARG_MEDIA_POSITION, mediaPosition); + b.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments)); + mediaIntent.putExtras(b); + ActivityOptionsCompat options = ActivityOptionsCompat + .makeSceneTransitionAnimation((Activity) context, layoutMediaBinding.media, statusToDeal.media_attachments.get(0).url); + // start the new activity + context.startActivity(mediaIntent, options.toBundle()); + }); + layoutMediaBinding.viewHide.setOnClickListener(v -> { + statusToDeal.sensitive = !statusToDeal.sensitive; + adapter.notifyItemChanged(holder.getBindingAdapterPosition()); + }); + + if (fullAttachement || singleImage) { + layoutMediaBinding.getRoot().setPadding(0, 0, 0, 10); + } else { + layoutMediaBinding.getRoot().setPadding(0, 0, 10, 0); + } + + } + + @Override + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + super.onAttachedToRecyclerView(recyclerView); + + mRecyclerView = recyclerView; + } + private static boolean mediaObfuscated(Status status) { //Media is not sensitive and doesn't have a spoiler text if (!status.isMediaObfuscated) { @@ -2146,6 +2159,90 @@ public class StatusAdapter extends RecyclerView.Adapter return position; } + public static void applyColor(Context context, StatusViewHolder holder) { + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; + boolean customLight = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOMIZE_LIGHT_COLORS), false); + boolean customDark = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOMIZE_DARK_COLORS), false); + int theme_icons_color = -1; + int theme_statuses_color = -1; + int theme_boost_header_color = -1; + int theme_text_color = -1; + int theme_text_header_1_line = -1; + int theme_text_header_2_line = -1; + int link_color = -1; + if (currentNightMode == Configuration.UI_MODE_NIGHT_NO) { //LIGHT THEME + if (customLight) { + theme_icons_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_ICON), -1); + theme_statuses_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_BACKGROUND), -1); + theme_boost_header_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_BOOST_HEADER), -1); + theme_text_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_TEXT), -1); + theme_text_header_1_line = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_DISPLAY_NAME), -1); + theme_text_header_2_line = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_USERNAME), -1); + link_color = sharedpreferences.getInt(context.getString(R.string.SET_LIGHT_LINK), -1); + } + } else { + if (customDark) { + theme_icons_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_ICON), -1); + theme_statuses_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_BACKGROUND), -1); + theme_boost_header_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_BOOST_HEADER), -1); + theme_text_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_TEXT), -1); + theme_text_header_1_line = sharedpreferences.getInt(context.getString(R.string.SET_DARK_DISPLAY_NAME), -1); + theme_text_header_2_line = sharedpreferences.getInt(context.getString(R.string.SET_DARK_USERNAME), -1); + link_color = sharedpreferences.getInt(context.getString(R.string.SET_DARK_LINK), -1); + } + } + + if (theme_icons_color != -1) { + Helper.changeDrawableColor(context, holder.binding.actionButtonReply, theme_icons_color); + Helper.changeDrawableColor(context, holder.binding.statusAddCustomEmoji, theme_icons_color); + Helper.changeDrawableColor(context, holder.binding.statusEmoji, theme_icons_color); + Helper.changeDrawableColor(context, holder.binding.actionButtonMore, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_round_star_24, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_round_repeat_24, theme_icons_color); + Helper.changeDrawableColor(context, holder.binding.visibility, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_round_star_border_24, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_person, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_bot, theme_icons_color); + Helper.changeDrawableColor(context, R.drawable.ic_round_reply_24, theme_icons_color); + holder.binding.actionButtonFavorite.setInActiveImageTintColor(theme_icons_color); + holder.binding.actionButtonBookmark.setInActiveImageTintColor(theme_icons_color); + holder.binding.actionButtonBoost.setInActiveImageTintColor(theme_icons_color); + holder.binding.replyCount.setTextColor(theme_icons_color); + } + if (theme_statuses_color != -1) { + holder.binding.cardviewContainer.setBackgroundColor(theme_statuses_color); + holder.binding.translationLabel.setBackgroundColor(theme_statuses_color); + } + if (theme_boost_header_color != -1) { + holder.binding.statusBoosterInfo.setBackgroundColor(theme_boost_header_color); + } + if (theme_text_color != -1) { + holder.binding.statusContent.setTextColor(theme_text_color); + holder.binding.statusContentTranslated.setTextColor(theme_text_color); + holder.binding.spoiler.setTextColor(theme_text_color); + holder.binding.dateShort.setTextColor(theme_text_color); + holder.binding.poll.pollInfo.setTextColor(theme_text_color); + holder.binding.cardDescription.setTextColor(theme_text_color); + holder.binding.time.setTextColor(theme_text_color); + holder.binding.reblogsCount.setTextColor(theme_text_color); + holder.binding.favoritesCount.setTextColor(theme_text_color); + holder.binding.favoritesCount.setTextColor(theme_text_color); + Helper.changeDrawableColor(context, holder.binding.repeatInfo, theme_text_color); + Helper.changeDrawableColor(context, holder.binding.favInfo, theme_text_color); + Helper.changeDrawableColor(context, R.drawable.ic_baseline_lock_24, theme_text_color); + } + if (theme_text_header_1_line != -1) { + holder.binding.displayName.setTextColor(theme_text_header_1_line); + } + if (theme_text_header_2_line != -1) { + holder.binding.username.setTextColor(theme_text_header_2_line); + } + if (link_color != -1) { + holder.binding.cardUrl.setTextColor(link_color); + } + } + @Override public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) { //Nothing to do with hidden statuses @@ -2155,12 +2252,22 @@ public class StatusAdapter extends RecyclerView.Adapter Status status = statusList.get(position); if (viewHolder.getItemViewType() == STATUS_VISIBLE) { StatusViewHolder holder = (StatusViewHolder) viewHolder; + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) { + holder.binding.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context)); + holder.binding.dividerCard.setVisibility(View.GONE); + } StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class); SearchVM searchVM = new ViewModelProvider((ViewModelStoreOwner) context).get(SearchVM.class); - statusManagement(context, statusesVM, searchVM, holder, this, statusList, status, timelineType, minified, canBeFederated, checkRemotely, fetchMoreCallBack); + statusManagement(context, statusesVM, searchVM, holder, mRecyclerView, this, statusList, status, timelineType, minified, canBeFederated, checkRemotely, fetchMoreCallBack); + applyColor(context, holder); } else if (viewHolder.getItemViewType() == STATUS_FILTERED_HIDE) { StatusViewHolder holder = (StatusViewHolder) viewHolder; - + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) { + holder.binding.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context)); + holder.binding.dividerCard.setVisibility(View.GONE); + } if (status.isFetchMore && fetchMoreCallBack != null) { holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE); holder.bindingFilteredHide.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> { @@ -2191,10 +2298,8 @@ public class StatusAdapter extends RecyclerView.Adapter } else { holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.GONE); } - } else if (viewHolder.getItemViewType() == STATUS_FILTERED) { StatusViewHolder holder = (StatusViewHolder) viewHolder; - holder.bindingFiltered.filteredText.setText(context.getString(R.string.filtered_by, status.filteredByApp.title)); holder.bindingFiltered.displayButton.setOnClickListener(v -> { status.filteredByApp = null; @@ -2231,7 +2336,6 @@ public class StatusAdapter extends RecyclerView.Adapter } else { holder.bindingFiltered.layoutFetchMore.fetchMoreContainer.setVisibility(View.GONE); } - } else if (viewHolder.getItemViewType() == STATUS_ART) { StatusViewHolder holder = (StatusViewHolder) viewHolder; MastodonHelper.loadPPMastodon(holder.bindingArt.artPp, status.account); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusDraftAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusDraftAdapter.java index 13403016..a9b84990 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusDraftAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusDraftAdapter.java @@ -17,12 +17,15 @@ package app.fedilab.android.ui.drawer; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import java.io.File; @@ -68,6 +71,12 @@ public class StatusDraftAdapter extends RecyclerView.Adapter 0) { holder.binding.statusContent.setText(statusDraft.statusDraftList.get(0).text, TextView.BufferType.SPANNABLE); @@ -87,7 +96,7 @@ public class StatusDraftAdapter extends RecyclerView.Adapter { + holder.binding.cardviewContainer.setOnClickListener(v -> { Intent intent = new Intent(context, ComposeActivity.class); intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); context.startActivity(intent); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java index 66c2504c..33dd4c86 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusHistoryAdapter.java @@ -56,13 +56,13 @@ public class StatusHistoryAdapter extends RecyclerView.Adapter(holder.binding.statusContent)), + new WeakReference<>(holder.binding.statusContent), null), TextView.BufferType.SPANNABLE); if (status.spoiler_text != null && !status.spoiler_text.trim().isEmpty()) { holder.binding.spoiler.setVisibility(View.VISIBLE); holder.binding.spoiler.setText( status.getSpanSpoiler(context, - new WeakReference<>(holder.binding.spoiler)), + new WeakReference<>(holder.binding.spoiler), null), TextView.BufferType.SPANNABLE); } else { holder.binding.spoiler.setVisibility(View.GONE); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusScheduledAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusScheduledAdapter.java index 011fadbe..5e1e458d 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusScheduledAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusScheduledAdapter.java @@ -121,7 +121,7 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter { + holder.binding.cardviewContainer.setOnClickListener(v -> { if (statusDraft != null) { Intent intent = new Intent(context, ComposeActivity.class); intent.putExtra(Helper.ARG_STATUS_DRAFT, statusDraft); diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/SuggestionAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/SuggestionAdapter.java index c1a817a4..1637004c 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/SuggestionAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/SuggestionAdapter.java @@ -18,6 +18,7 @@ package app.fedilab.android.ui.drawer; import android.app.Activity; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; @@ -28,6 +29,7 @@ import androidx.annotation.NonNull; import androidx.core.app.ActivityOptionsCompat; import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelStoreOwner; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import java.lang.ref.WeakReference; @@ -76,7 +78,11 @@ public class SuggestionAdapter extends RecyclerView.Adapter { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/TagAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/TagAdapter.java index 7f7a8a77..58c9969f 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/TagAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/TagAdapter.java @@ -16,11 +16,14 @@ package app.fedilab.android.ui.drawer; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import com.github.mikephil.charting.components.Description; @@ -52,6 +55,13 @@ public class TagAdapter extends RecyclerView.Adapter { public static void tagManagement(Context context, TagViewHolder tagViewHolder, Tag tag) { tagViewHolder.binding.tagName.setText(String.format("#%s", tag.name)); + + SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context); + if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) { + tagViewHolder.binding.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context)); + tagViewHolder.binding.dividerCard.setVisibility(View.GONE); + } + List trendsEntry = new ArrayList<>(); List historyList = tag.history; diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/admin/AdminAccountAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/admin/AdminAccountAdapter.java index 16968e41..772c5585 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/admin/AdminAccountAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/admin/AdminAccountAdapter.java @@ -17,16 +17,20 @@ package app.fedilab.android.ui.drawer.admin; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.RecyclerView; import java.util.List; import java.util.Locale; +import app.fedilab.android.R; import app.fedilab.android.activities.admin.AdminAccountActivity; import app.fedilab.android.client.entities.api.admin.AdminAccount; import app.fedilab.android.databinding.DrawerAdminAccountBinding; @@ -63,8 +67,15 @@ public class AdminAccountAdapter extends RecyclerView.Adapter { + holder.binding.cardviewContainer.setOnClickListener(v -> { Intent intent = new Intent(context, AdminAccountActivity.class); Bundle b = new Bundle(); b.putSerializable(Helper.ARG_ACCOUNT, adminAccount); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomDarkSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomDarkSettings.java new file mode 100644 index 00000000..7a1e3772 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomDarkSettings.java @@ -0,0 +1,57 @@ +package app.fedilab.android.ui.fragment.settings; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + + +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; + +import app.fedilab.android.R; + +public class FragmentCustomDarkSettings extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_custom_dark); + createPref(); + } + + private void createPref() { + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + + } + + @Override + public void onResume() { + super.onResume(); + + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + +} diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomLightSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomLightSettings.java new file mode 100644 index 00000000..d35e5cf8 --- /dev/null +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentCustomLightSettings.java @@ -0,0 +1,57 @@ +package app.fedilab.android.ui.fragment.settings; +/* Copyright 2022 Thomas Schneider + * + * This file is a part of Fedilab + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with Fedilab; if not, + * see . */ + + +import android.content.SharedPreferences; +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; + +import app.fedilab.android.R; + +public class FragmentCustomLightSettings extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.pref_custom_light); + createPref(); + } + + private void createPref() { + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + + } + + @Override + public void onResume() { + super.onResume(); + + getPreferenceScreen().getSharedPreferences() + .registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + getPreferenceScreen().getSharedPreferences() + .unregisterOnSharedPreferenceChangeListener(this); + } + + +} diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java index 72f63533..b6b407e5 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/settings/FragmentThemingSettings.java @@ -18,7 +18,11 @@ package app.fedilab.android.ui.fragment.settings; import android.content.SharedPreferences; import android.os.Bundle; +import androidx.appcompat.app.AlertDialog; +import androidx.navigation.NavOptions; +import androidx.navigation.Navigation; import androidx.preference.ListPreference; +import androidx.preference.Preference; import androidx.preference.PreferenceFragmentCompat; import app.fedilab.android.R; @@ -89,6 +93,61 @@ public class FragmentThemingSettings extends PreferenceFragmentCompat implements if (SET_THEME_DEFAULT_DARK != null) { SET_THEME_DEFAULT_DARK.getContext().setTheme(Helper.dialogStyle()); } + + Preference SET_CUSTOMIZE_LIGHT_COLORS_ACTION = findPreference(getString(R.string.SET_CUSTOMIZE_LIGHT_COLORS_ACTION)); + if (SET_CUSTOMIZE_LIGHT_COLORS_ACTION != null) { + SET_CUSTOMIZE_LIGHT_COLORS_ACTION.setOnPreferenceClickListener(preference -> { + NavOptions.Builder navBuilder = new NavOptions.Builder(); + navBuilder.setEnterAnim(R.anim.enter).setExitAnim(R.anim.exit).setPopEnterAnim(R.anim.pop_enter).setPopExitAnim(R.anim.pop_exit); + + Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(R.id.FragmentCustomLightSettings, null, navBuilder.build()); + return true; + }); + } + + Preference SET_CUSTOMIZE_DARK_COLORS_ACTION = findPreference(getString(R.string.SET_CUSTOMIZE_DARK_COLORS_ACTION)); + if (SET_CUSTOMIZE_DARK_COLORS_ACTION != null) { + SET_CUSTOMIZE_DARK_COLORS_ACTION.setOnPreferenceClickListener(preference -> { + NavOptions.Builder navBuilder = new NavOptions.Builder(); + navBuilder.setEnterAnim(R.anim.enter).setExitAnim(R.anim.exit).setPopEnterAnim(R.anim.pop_enter).setPopExitAnim(R.anim.pop_exit); + Navigation.findNavController(requireActivity(), R.id.fragment_container).navigate(R.id.FragmentCustomDarkSettings, null, navBuilder.build()); + return true; + }); + } + + Preference SET_RESET_CUSTOM_COLOR = findPreference(getString(R.string.SET_RESET_CUSTOM_COLOR)); + if (SET_RESET_CUSTOM_COLOR != null) { + SET_RESET_CUSTOM_COLOR.getContext().setTheme(Helper.dialogStyle()); + SET_RESET_CUSTOM_COLOR.setOnPreferenceClickListener(preference -> { + AlertDialog.Builder resetConfirm = new AlertDialog.Builder(requireActivity(), Helper.dialogStyle()); + resetConfirm.setMessage(getString(R.string.reset_color)); + resetConfirm.setNegativeButton(R.string.no, (dialog, which) -> dialog.dismiss()); + resetConfirm.setPositiveButton(R.string.reset, (dialog, which) -> { + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); + if (sharedPreferences != null) { + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_BACKGROUND)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_BOOST_HEADER)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_DISPLAY_NAME)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_USERNAME)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_TEXT)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_LINK)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_LIGHT_ICON)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_BACKGROUND)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_BOOST_HEADER)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_DISPLAY_NAME)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_USERNAME)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_TEXT)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_LINK)).apply(); + sharedPreferences.edit().remove(getString(R.string.SET_DARK_ICON)).apply(); + + } + + dialog.dismiss(); + }); + resetConfirm.show(); + return true; + }); + } } } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java index 2262edd1..ded9e0af 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonConversation.java @@ -140,7 +140,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati timelineParams.fetchingMissing = fetchingMissing; - if (useCache) { + if (useCache && direction != FragmentMastodonTimeline.DIRECTION.SCROLL_TOP && direction != FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { getCachedConversations(direction, fetchingMissing, timelineParams); } else { getLiveConversations(direction, fetchingMissing, timelineParams, conversationToUpdate); @@ -150,7 +150,7 @@ public class FragmentMastodonConversation extends Fragment implements Conversati private void getCachedConversations(FragmentMastodonTimeline.DIRECTION direction, boolean fetchingMissing, TimelinesVM.TimelineParams timelineParams) { if (direction == null) { - timelinesVM.getConversations(conversationList, timelineParams) + timelinesVM.getConversationsCache(conversationList, timelineParams) .observe(getViewLifecycleOwner(), conversationsCached -> { if (conversationsCached == null || conversationsCached.conversations == null || conversationsCached.conversations.size() == 0) { getLiveConversations(null, fetchingMissing, timelineParams, null); @@ -179,13 +179,18 @@ public class FragmentMastodonConversation extends Fragment implements Conversati } }); } else if (direction == FragmentMastodonTimeline.DIRECTION.REFRESH) { - timelinesVM.getConversations(conversationList, timelineParams) + timelinesVM.getConversationsCache(conversationList, timelineParams) .observe(getViewLifecycleOwner(), notificationsRefresh -> { - if (conversationAdapter != null) { - dealWithPagination(notificationsRefresh, FragmentMastodonTimeline.DIRECTION.REFRESH, true, null); + if (notificationsRefresh == null || notificationsRefresh.conversations == null || notificationsRefresh.conversations.size() == 0) { + getLiveConversations(direction, fetchingMissing, timelineParams, null); } else { - initializeConversationCommonView(notificationsRefresh); + if (conversationAdapter != null) { + dealWithPagination(notificationsRefresh, FragmentMastodonTimeline.DIRECTION.REFRESH, true, null); + } else { + initializeConversationCommonView(notificationsRefresh); + } } + }); } } diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java index 3a07d55e..0bef27f8 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonNotification.java @@ -387,7 +387,7 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } timelineParams.excludeType = getExcludeType(); timelineParams.fetchingMissing = fetchingMissing; - if (useCache) { + if (useCache && direction != FragmentMastodonTimeline.DIRECTION.SCROLL_TOP && direction != FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { getCachedNotifications(direction, fetchingMissing, timelineParams); } else { getLiveNotifications(direction, fetchingMissing, timelineParams, notificationToUpdate); @@ -430,10 +430,14 @@ public class FragmentMastodonNotification extends Fragment implements Notificati } else if (direction == FragmentMastodonTimeline.DIRECTION.REFRESH) { notificationsVM.getNotifications(notificationList, timelineParams) .observe(getViewLifecycleOwner(), notificationsRefresh -> { - if (notificationAdapter != null) { - dealWithPagination(notificationsRefresh, FragmentMastodonTimeline.DIRECTION.REFRESH, true, null); + if (notificationsRefresh == null || notificationsRefresh.notifications == null || notificationsRefresh.notifications.size() == 0) { + getLiveNotifications(direction, fetchingMissing, timelineParams, null); } else { - initializeNotificationView(notificationsRefresh); + if (notificationAdapter != null) { + dealWithPagination(notificationsRefresh, FragmentMastodonTimeline.DIRECTION.REFRESH, true, null); + } else { + initializeNotificationView(notificationsRefresh); + } } }); } diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java index 16271d4e..cb9d624c 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/NotificationsVM.java @@ -24,6 +24,7 @@ import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -64,8 +65,13 @@ public class NotificationsVM extends AndroidViewModel { super(application); } + private static void sortDesc(List notificationList) { + Collections.sort(notificationList, (obj1, obj2) -> obj2.id.compareToIgnoreCase(obj1.id)); + } + private static void addFetchMoreNotifications(List notificationList, List timelineNotifications, TimelinesVM.TimelineParams timelineParams) throws DBException { if (notificationList != null && notificationList.size() > 0 && timelineNotifications != null && timelineNotifications.size() > 0) { + sortDesc(notificationList); if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (notificationList.get(notificationList.size() - 1).id.compareToIgnoreCase(timelineNotifications.get(0).id) > 0) { diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index d94d1ad0..4b98de70 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -29,6 +29,7 @@ import androidx.lifecycle.MutableLiveData; import androidx.preference.PreferenceManager; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.TimeUnit; @@ -90,8 +91,18 @@ public class TimelinesVM extends AndroidViewModel { super(application); } + + private static void sortDesc(List statusList) { + Collections.sort(statusList, (obj1, obj2) -> obj2.id.compareToIgnoreCase(obj1.id)); + } + + private static void sortDescConv(List conversationList) { + Collections.sort(conversationList, (obj1, obj2) -> obj2.id.compareToIgnoreCase(obj1.id)); + } + private static void addFetchMore(List statusList, List timelineStatuses, TimelineParams timelineParams) throws DBException { if (statusList != null && statusList.size() > 0 && timelineStatuses != null && timelineStatuses.size() > 0) { + sortDesc(statusList); if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (statusList.get(statusList.size() - 1).id.compareToIgnoreCase(timelineStatuses.get(0).id) > 0) { @@ -114,6 +125,7 @@ public class TimelinesVM extends AndroidViewModel { private static void addFetchMoreConversation(List conversationList, List timelineConversations, TimelineParams timelineParams) throws DBException { if (conversationList != null && conversationList.size() > 0 && timelineConversations != null && timelineConversations.size() > 0) { + sortDescConv(conversationList); if (timelineParams.direction == FragmentMastodonTimeline.DIRECTION.REFRESH || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.SCROLL_TOP || timelineParams.direction == FragmentMastodonTimeline.DIRECTION.FETCH_NEW) { //When refreshing/scrolling to TOP, if last statuses fetched has a greater id from newest in cache, there is potential hole if (conversationList.get(conversationList.size() - 1).id.compareToIgnoreCase(timelineConversations.get(0).id) > 0) { diff --git a/app/src/main/res/drawable/ic_baseline_bookmark_24.xml b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml index 1355573f..78ef4991 100644 --- a/app/src/main/res/drawable/ic_baseline_bookmark_24.xml +++ b/app/src/main/res/drawable/ic_baseline_bookmark_24.xml @@ -5,6 +5,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/app/src/main/res/drawable/ic_baseline_photo_24.xml b/app/src/main/res/drawable/ic_baseline_photo_24.xml new file mode 100644 index 00000000..0a221c91 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_photo_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_baseline_repeat_24.xml b/app/src/main/res/drawable/ic_baseline_repeat_24.xml index 5b0f044a..74e2ec74 100644 --- a/app/src/main/res/drawable/ic_baseline_repeat_24.xml +++ b/app/src/main/res/drawable/ic_baseline_repeat_24.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/drawable/ic_repeat.xml b/app/src/main/res/drawable/ic_repeat.xml index 6b566159..99a7787e 100644 --- a/app/src/main/res/drawable/ic_repeat.xml +++ b/app/src/main/res/drawable/ic_repeat.xml @@ -1,11 +1,10 @@ + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + android:pathData="M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z" /> diff --git a/app/src/main/res/drawable/ic_round_bookmark_24.xml b/app/src/main/res/drawable/ic_round_bookmark_24.xml new file mode 100644 index 00000000..fdc2c64d --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bookmark_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_bookmark_border_24.xml b/app/src/main/res/drawable/ic_round_bookmark_border_24.xml new file mode 100644 index 00000000..e3a3ff54 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_bookmark_border_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_more_horiz_24.xml b/app/src/main/res/drawable/ic_round_more_horiz_24.xml new file mode 100644 index 00000000..e7295060 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_more_horiz_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_repeat_24.xml b/app/src/main/res/drawable/ic_round_repeat_24.xml new file mode 100644 index 00000000..7d7446d4 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_repeat_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_reply_24.xml b/app/src/main/res/drawable/ic_round_reply_24.xml new file mode 100644 index 00000000..e063311b --- /dev/null +++ b/app/src/main/res/drawable/ic_round_reply_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_star_24.xml b/app/src/main/res/drawable/ic_round_star_24.xml new file mode 100644 index 00000000..3421678a --- /dev/null +++ b/app/src/main/res/drawable/ic_round_star_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_round_star_border_24.xml b/app/src/main/res/drawable/ic_round_star_border_24.xml new file mode 100644 index 00000000..7edb5843 --- /dev/null +++ b/app/src/main/res/drawable/ic_round_star_border_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/drawable/ic_star_outline.xml b/app/src/main/res/drawable/ic_star_outline.xml index 70463a76..40bb88cc 100644 --- a/app/src/main/res/drawable/ic_star_outline.xml +++ b/app/src/main/res/drawable/ic_star_outline.xml @@ -1,9 +1,9 @@ + android:viewportWidth="24" + android:viewportHeight="24"> diff --git a/app/src/main/res/layout/drawer_account.xml b/app/src/main/res/layout/drawer_account.xml index 75a4731a..449c8bef 100644 --- a/app/src/main/res/layout/drawer_account.xml +++ b/app/src/main/res/layout/drawer_account.xml @@ -14,16 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginTop="6dp" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -154,4 +159,4 @@ - + diff --git a/app/src/main/res/layout/drawer_account_list.xml b/app/src/main/res/layout/drawer_account_list.xml index 06c94694..78b1b0af 100644 --- a/app/src/main/res/layout/drawer_account_list.xml +++ b/app/src/main/res/layout/drawer_account_list.xml @@ -14,15 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginHorizontal="6dp" + android:layout_marginTop="6dp" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -71,14 +77,14 @@ - + diff --git a/app/src/main/res/layout/drawer_admin_account.xml b/app/src/main/res/layout/drawer_admin_account.xml index 11be1312..2b515294 100644 --- a/app/src/main/res/layout/drawer_admin_account.xml +++ b/app/src/main/res/layout/drawer_admin_account.xml @@ -1,16 +1,23 @@ - + android:layout_marginTop="6dp" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> + - + diff --git a/app/src/main/res/layout/drawer_announcement.xml b/app/src/main/res/layout/drawer_announcement.xml index b7fe3621..4825a7be 100644 --- a/app/src/main/res/layout/drawer_announcement.xml +++ b/app/src/main/res/layout/drawer_announcement.xml @@ -14,19 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -96,4 +98,4 @@ - + diff --git a/app/src/main/res/layout/drawer_conversation.xml b/app/src/main/res/layout/drawer_conversation.xml index 3fa599d2..8da244c4 100644 --- a/app/src/main/res/layout/drawer_conversation.xml +++ b/app/src/main/res/layout/drawer_conversation.xml @@ -14,17 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginTop="6dp" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -115,4 +119,4 @@ tools:visibility="visible" /> - + diff --git a/app/src/main/res/layout/drawer_domain_block.xml b/app/src/main/res/layout/drawer_domain_block.xml index 81edbc78..653b54c4 100644 --- a/app/src/main/res/layout/drawer_domain_block.xml +++ b/app/src/main/res/layout/drawer_domain_block.xml @@ -14,13 +14,20 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see . --> - + android:layout_marginHorizontal="6dp" + android:layout_marginTop="6dp" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -51,4 +58,4 @@ android:padding="6dp" app:icon="@drawable/ic_baseline_delete_24" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_follow.xml b/app/src/main/res/layout/drawer_follow.xml index 0fcc8e74..a3cf4282 100644 --- a/app/src/main/res/layout/drawer_follow.xml +++ b/app/src/main/res/layout/drawer_follow.xml @@ -14,15 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -48,6 +54,7 @@ tools:text="User asked to follow you" /> - + diff --git a/app/src/main/res/layout/drawer_instance_reg.xml b/app/src/main/res/layout/drawer_instance_reg.xml index 0f97003a..7eea23d1 100644 --- a/app/src/main/res/layout/drawer_instance_reg.xml +++ b/app/src/main/res/layout/drawer_instance_reg.xml @@ -14,14 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see . --> - + android:id="@+id/cardview_container" + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -49,7 +56,7 @@ android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="6dp" - android:textAppearance="@style/TextAppearance.Material3.HeadlineMedium" + android:textAppearance="@style/TextAppearance.Material3.TitleMedium" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/instance_pp" app:layout_constraintTop_toTopOf="parent" @@ -99,4 +106,4 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status.xml b/app/src/main/res/layout/drawer_status.xml index 3a741fe3..23a23740 100644 --- a/app/src/main/res/layout/drawer_status.xml +++ b/app/src/main/res/layout/drawer_status.xml @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - - - + app:cardElevation="0dp" + app:strokeWidth="0dp"> + + + + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintVertical_bias="0.0"> - + app:srcCompat="@drawable/ic_round_reply_24" /> @@ -638,17 +644,15 @@ app:layout_constraintEnd_toStartOf="@+id/action_button_bookmark" app:layout_constraintStart_toEndOf="@+id/action_button_boost" app:layout_constraintTop_toTopOf="parent" - android:layout_width="28dp" - android:layout_height="28dp" + android:layout_width="48dp" + android:layout_height="48dp" android:layout_gravity="center" - android:layout_marginStart="12dp" - android:layout_marginTop="2dp" android:adjustViewBounds="true" android:contentDescription="@string/favourite_add" - app:sparkbutton_activeImage="@drawable/ic_baseline_star_24" + app:sparkbutton_activeImage="@drawable/ic_round_star_24" app:sparkbutton_animationSpeed="1.5" - app:sparkbutton_iconSize="28dp" - app:sparkbutton_inActiveImage="@drawable/ic_star_outline" + app:sparkbutton_iconSize="24dp" + app:sparkbutton_inActiveImage="@drawable/ic_round_star_border_24" app:sparkbutton_primaryColor="@color/marked_icon" app:sparkbutton_secondaryColor="@color/marked_icon" /> @@ -658,31 +662,29 @@ app:layout_constraintEnd_toStartOf="@+id/status_add_custom_emoji" app:layout_constraintStart_toEndOf="@+id/action_button_favorite" app:layout_constraintTop_toTopOf="parent" - android:layout_width="28dp" - android:layout_height="28dp" + android:layout_width="48dp" + android:layout_height="48dp" android:layout_gravity="center" - android:layout_marginStart="12dp" - android:adjustViewBounds="true" android:contentDescription="@string/bookmark_add" - app:sparkbutton_activeImage="@drawable/ic_baseline_bookmark_24" + app:sparkbutton_activeImage="@drawable/ic_round_bookmark_24" app:sparkbutton_animationSpeed="1.5" app:sparkbutton_iconSize="24dp" - app:sparkbutton_inActiveImage="@drawable/ic_baseline_bookmark_border_24" + app:sparkbutton_inActiveImage="@drawable/ic_round_bookmark_border_24" app:sparkbutton_primaryColor="@color/marked_icon" app:sparkbutton_secondaryColor="@color/marked_icon" /> - - - + app:srcCompat="@drawable/ic_round_more_horiz_24" /> - + - + diff --git a/app/src/main/res/layout/drawer_status_draft.xml b/app/src/main/res/layout/drawer_status_draft.xml index 1eb24ce4..20d4c9ef 100644 --- a/app/src/main/res/layout/drawer_status_draft.xml +++ b/app/src/main/res/layout/drawer_status_draft.xml @@ -14,15 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -106,4 +112,4 @@ - + diff --git a/app/src/main/res/layout/drawer_status_filtered.xml b/app/src/main/res/layout/drawer_status_filtered.xml index 69154e28..ad55cf66 100644 --- a/app/src/main/res/layout/drawer_status_filtered.xml +++ b/app/src/main/res/layout/drawer_status_filtered.xml @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -78,4 +81,4 @@ tools:visibility="visible" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status_filtered_hide.xml b/app/src/main/res/layout/drawer_status_filtered_hide.xml index 4b7b3223..a4b85bdf 100644 --- a/app/src/main/res/layout/drawer_status_filtered_hide.xml +++ b/app/src/main/res/layout/drawer_status_filtered_hide.xml @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -47,4 +50,4 @@ app:layout_constraintTop_toTopOf="parent" tools:visibility="visible" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status_history.xml b/app/src/main/res/layout/drawer_status_history.xml index 0522d2c6..9bdee310 100644 --- a/app/src/main/res/layout/drawer_status_history.xml +++ b/app/src/main/res/layout/drawer_status_history.xml @@ -14,17 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -100,4 +104,4 @@ tools:text="@tools:sample/lorem/random" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_status_scheduled.xml b/app/src/main/res/layout/drawer_status_scheduled.xml index b22296a2..d2c36eb9 100644 --- a/app/src/main/res/layout/drawer_status_scheduled.xml +++ b/app/src/main/res/layout/drawer_status_scheduled.xml @@ -14,15 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -96,4 +102,4 @@ - + diff --git a/app/src/main/res/layout/drawer_status_simple.xml b/app/src/main/res/layout/drawer_status_simple.xml index f7412709..baa53c42 100644 --- a/app/src/main/res/layout/drawer_status_simple.xml +++ b/app/src/main/res/layout/drawer_status_simple.xml @@ -14,17 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -98,4 +102,4 @@ tools:text="@tools:sample/lorem/random" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_suggestion.xml b/app/src/main/res/layout/drawer_suggestion.xml index 8ed647a5..a8eba685 100644 --- a/app/src/main/res/layout/drawer_suggestion.xml +++ b/app/src/main/res/layout/drawer_suggestion.xml @@ -14,15 +14,21 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see --> - + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -107,4 +113,4 @@ - + diff --git a/app/src/main/res/layout/drawer_tag.xml b/app/src/main/res/layout/drawer_tag.xml index 96667104..1819db94 100644 --- a/app/src/main/res/layout/drawer_tag.xml +++ b/app/src/main/res/layout/drawer_tag.xml @@ -14,12 +14,20 @@ You should have received a copy of the GNU General Public License along with Fedilab; if not, see . --> - + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/cardview_container" + android:layout_marginHorizontal="@dimen/card_margin" + android:layout_marginTop="@dimen/card_margin" + android:clipChildren="false" + android:clipToPadding="false" + app:cardElevation="0dp" + app:strokeWidth="0dp"> @@ -64,4 +72,4 @@ android:layout_width="100dp" android:layout_height="50dp" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_media.xml b/app/src/main/res/layout/layout_media.xml index fa259a3b..3788c1b6 100644 --- a/app/src/main/res/layout/layout_media.xml +++ b/app/src/main/res/layout/layout_media.xml @@ -12,8 +12,7 @@ app:layout_constraintTop_toTopOf="parent" android:id="@+id/media" android:layout_width="match_parent" - android:layout_height="200dp" - android:scaleType="centerCrop" + android:layout_height="wrap_content" tools:ignore="ContentDescription" /> + + + + + diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 349c2cf8..385929bb 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -735,4 +735,19 @@ لون ديناميكي لا يعجبني ليس شيئاً تريد رؤيته + تسجيل جديد (المشرفون) + تقرير جديد (المشرفون) + فتح باستخدام حساب آخر + رفض ملفات الوسائط + رفض التقارير + سياسة الخصوصية + النطاقات + الاحتفاظ بالإشعارات + رفض التقارير + رفض الوسائط + الشدة + تعليق خاص + تشويش اسم النطاق + المظهر الداكن الافتراضي + تعليق للعامة \ No newline at end of file diff --git a/app/src/main/res/values-ber/strings.xml b/app/src/main/res/values-ber/strings.xml index 9b6a0da2..b9a0b01e 100644 --- a/app/src/main/res/values-ber/strings.xml +++ b/app/src/main/res/values-ber/strings.xml @@ -497,7 +497,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index d599792a..d5af3a38 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-br/strings.xml b/app/src/main/res/values-br/strings.xml index e8e92a23..4eaaf9a0 100644 --- a/app/src/main/res/values-br/strings.xml +++ b/app/src/main/res/values-br/strings.xml @@ -554,7 +554,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 90c41342..0f48d25a 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -540,7 +540,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-cy/strings.xml b/app/src/main/res/values-cy/strings.xml index c466747e..f0c77e66 100644 --- a/app/src/main/res/values-cy/strings.xml +++ b/app/src/main/res/values-cy/strings.xml @@ -549,7 +549,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 3c625689..b6128f34 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -529,7 +529,7 @@ Επέλεξε μία κίνηση Μετάφραση Χρώμα κειμένου - Change the text color in pots + Change the text color in messages Χρήση ενός προσαρμοσμένου θέματος Θεματισμός Έγινε εξαγωγή του θέματος diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 13d603bb..21cd5d07 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -530,7 +530,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 527bc0af..2b1d608c 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 0b99968f..adc2829f 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 44ca0daa..20424b2d 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-hy/strings.xml b/app/src/main/res/values-hy/strings.xml index 990e9c5a..92a15200 100644 --- a/app/src/main/res/values-hy/strings.xml +++ b/app/src/main/res/values-hy/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 90780c30..a5cf3611 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -525,7 +525,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 72ddc92f..6c622bd8 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index b4966bac..4fa0fb93 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -524,7 +524,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 14903586..12e17ad0 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 031cb493..90a50a64 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,6 +1,10 @@ + + + + - + + - + + + + + + + + + + + + diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index e47451ae..c7d4aee9 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -528,7 +528,7 @@ Make an action Oversettelse Tekstfarge - Change the text color in pots + Change the text color in messages Bruk en egendefinert drakt Theming The theme was exported diff --git a/app/src/main/res/values-oc/strings.xml b/app/src/main/res/values-oc/strings.xml index b63a0d4c..54dc93c6 100644 --- a/app/src/main/res/values-oc/strings.xml +++ b/app/src/main/res/values-oc/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 2ffafd2a..7689d731 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -546,7 +546,7 @@ Make an action Tłumaczenie Kolor tekstu - Change the text color in pots + Change the text color in messages Użyj niestandardowego motywu Motyw Motyw został wyeksportowany diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 661f0daa..1838e8e8 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -534,7 +534,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index dad15378..49d90eef 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -534,7 +534,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 6b8aa654..81d0dd82 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -529,7 +529,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 47d052a7..56199ff8 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -539,7 +539,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index bf1e021f..f9cad92b 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -534,7 +534,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 31c4245c..e59d52a1 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -540,7 +540,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5b63928f..f31664d8 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,69 +1,83 @@ - - #6750A4 - #6750A4 + #2F0C7A + #654DB2 #FFFFFF - #EADDFF - #21005D - #625B71 + #E8DEFF + #20005F + #5E44D4 #FFFFFF - #E8DEF8 - #1D192B - #7D5260 + #E5DEFF + #1B0063 + #4D51BE #FFFFFF - #FFD8E4 - #31111D - #B3261E + #E1E0FF + #04006D + #BA1A1A + #FFDAD6 #FFFFFF - #F9DEDC - #410E0B - #79747E - #FFFBFE - #1C1B1F - #FFFBFE - #1C1B1F - #E7E0EC - #49454F - #313033 + #410002 + #FFFBFF + #1C1B1E + #FFFBFF + #1C1B1E + #E6E0EC + #48454E + #79757F #F4EFF4 - #D0BCFF + #313033 + #CDBDFF #000000 - #6750A4 - #CAC4D0 + #654DB2 + #CAC4CF #000000 - #8c8dff - #381E72 - #4F378B - #EADDFF - #CCC2DC - #332D41 - #4A4458 - #E8DEF8 - #EFB8C8 - #492532 - #633B48 - #FFD8E4 - #F2B8B5 - #601410 - #8C1D18 - #F9DEDC + #CDBDFF + #361781 + #4D3398 + #E8DEFF + #C9BFFF + #2F009C + #4625BC + #E5DEFF + #C0C1FF + #1A1B8F + #3438A5 + #E1E0FF + #FFB4AB + #93000A + #690005 + #FFDAD6 + #1C1B1E + #E6E1E6 + #1C1B1E + #E6E1E6 + #48454E + #CAC4CF #938F99 - #1C1B1F - #E6E1E5 - #1C1B1F - #E6E1E5 - #49454F - #CAC4D0 - #E6E1E5 - #313033 - #6750A4 + #1C1B1E + #E6E1E6 + #654DB2 #000000 - #D0BCFF - #49454F + #CDBDFF + #48454E #000000 + #78909C + #B0BEC5 + + + #ff79c6 + #50fa7b + #f8f8f2 + #6272a4 + #ffb86c + #f1fa8c + #8be9fd + #282a36 + #44475a + #bd93f9 + #FFEA00 #42A5F5 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f1fc79aa..259a36f5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -574,7 +574,7 @@ Make an action Translation Text color - Change the text color in pots + Change the text color in messages Use a custom theme Theming The theme was exported @@ -703,6 +703,7 @@ Solarized (Light) Solarized (Dark) Black + Dracula LIGHT @@ -711,6 +712,7 @@ SOLARIZED_LIGHT SOLARIZED_DARK BLACK + DRACULA @@ -727,11 +729,13 @@ Dark Solarized (Dark) Black + Dracula DARK SOLARIZED_DARK BLACK + DRACULA @@ -1293,9 +1297,33 @@ SET_CAPITALIZE SET_THEME_BASE SET_DYNAMICCOLOR + SET_CARDVIEW + SET_CUSTOMIZE_LIGHT_COLORS + SET_CUSTOMIZE_LIGHT_COLORS_ACTION + SET_CUSTOMIZE_DARK_COLORS + SET_CUSTOMIZE_DARK_COLORS_ACTION + SET_RESET_CUSTOM_COLOR + SET_THEME_DEFAULT_LIGHT SET_THEME_DEFAULT_DARK + SET_DARK_BACKGROUND + SET_DARK_TEXT + SET_DARK_BOOST_HEADER + SET_DARK_DISPLAY_NAME + SET_DARK_USERNAME + SET_DARK_LINK + SET_DARK_ICON + + + SET_LIGHT_BACKGROUND + SET_LIGHT_TEXT + SET_LIGHT_BOOST_HEADER + SET_LIGHT_DISPLAY_NAME + SET_LIGHT_USERNAME + SET_LIGHT_LINK + SET_LIGHT_ICON + SYSTEM @@ -2011,4 +2039,13 @@ Align tonally with the color scheme of your personal wallpaper. Default light theme Default dark theme + Elevated cards + When enabled, items in timelines will have a shadow and an elevation. + Customize Light Theme + Allows to customize some elements in messages for the light theme. + Customize Dark Theme + Allows to customize some elements in messages for the dark theme. + Set custom colors + Light - Custom colors + Dark - Custom colors \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 0bb81b60..17c9d2c2 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,6 +1,9 @@ + + - +