Animate gif avatars (#1279)
* animate gif avatars * add setting to enable avatar animation * cleanup code
This commit is contained in:
parent
da1089184c
commit
83696b5c7f
40 changed files with 381 additions and 547 deletions
|
@ -78,6 +78,8 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
||||||
private var showingReblogs: Boolean = false
|
private var showingReblogs: Boolean = false
|
||||||
private var loadedAccount: Account? = null
|
private var loadedAccount: Account? = null
|
||||||
|
|
||||||
|
private var animateAvatar: Boolean = false
|
||||||
|
|
||||||
// fields for scroll animation
|
// fields for scroll animation
|
||||||
private var hideFab: Boolean = false
|
private var hideFab: Boolean = false
|
||||||
private var oldOffset: Int = 0
|
private var oldOffset: Int = 0
|
||||||
|
@ -120,7 +122,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
||||||
updateButtons()
|
updateButtons()
|
||||||
}
|
}
|
||||||
|
|
||||||
hideFab = PreferenceManager.getDefaultSharedPreferences(this).getBoolean("fabHide", false)
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false)
|
||||||
|
hideFab = sharedPrefs.getBoolean("fabHide", false)
|
||||||
|
|
||||||
loadResources()
|
loadResources()
|
||||||
setupToolbar()
|
setupToolbar()
|
||||||
|
@ -379,11 +383,16 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
||||||
*/
|
*/
|
||||||
private fun updateAccountAvatar() {
|
private fun updateAccountAvatar() {
|
||||||
loadedAccount?.let { account ->
|
loadedAccount?.let { account ->
|
||||||
|
|
||||||
|
loadAvatar(
|
||||||
|
account.avatar,
|
||||||
|
accountAvatarImageView,
|
||||||
|
resources.getDimensionPixelSize(R.dimen.avatar_radius_94dp),
|
||||||
|
animateAvatar
|
||||||
|
)
|
||||||
|
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(account.avatar)
|
.asBitmap()
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(accountAvatarImageView)
|
|
||||||
Glide.with(this)
|
|
||||||
.load(account.header)
|
.load(account.header)
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(accountHeaderImageView)
|
.into(accountHeaderImageView)
|
||||||
|
@ -430,10 +439,9 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
||||||
accountMovedDisplayName.text = movedAccount.name
|
accountMovedDisplayName.text = movedAccount.name
|
||||||
accountMovedUsername.text = getString(R.string.status_username_format, movedAccount.username)
|
accountMovedUsername.text = getString(R.string.status_username_format, movedAccount.username)
|
||||||
|
|
||||||
Glide.with(this)
|
val avatarRadius = resources.getDimensionPixelSize(R.dimen.avatar_radius_48dp)
|
||||||
.load(movedAccount.avatar)
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
loadAvatar(movedAccount.avatar, accountMovedAvatar, avatarRadius, animateAvatar)
|
||||||
.into(accountMovedAvatar)
|
|
||||||
|
|
||||||
accountMovedText.text = getString(R.string.account_moved_description, movedAccount.displayName)
|
accountMovedText.text = getString(R.string.account_moved_description, movedAccount.displayName)
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.content.SharedPreferences;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.res.AssetFileDescriptor;
|
import android.content.res.AssetFileDescriptor;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.PorterDuff;
|
import android.graphics.PorterDuff;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
@ -60,25 +61,6 @@ import android.widget.PopupMenu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.Px;
|
|
||||||
import androidx.annotation.StringRes;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
|
||||||
import androidx.appcompat.widget.Toolbar;
|
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.core.content.FileProvider;
|
|
||||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
|
||||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
|
||||||
import androidx.lifecycle.Lifecycle;
|
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import androidx.transition.TransitionManager;
|
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.snackbar.Snackbar;
|
import com.google.android.material.snackbar.Snackbar;
|
||||||
|
@ -103,6 +85,7 @@ import com.keylesspalace.tusky.service.SendTootService;
|
||||||
import com.keylesspalace.tusky.util.ComposeTokenizer;
|
import com.keylesspalace.tusky.util.ComposeTokenizer;
|
||||||
import com.keylesspalace.tusky.util.CountUpDownLatch;
|
import com.keylesspalace.tusky.util.CountUpDownLatch;
|
||||||
import com.keylesspalace.tusky.util.DownsizeImageTask;
|
import com.keylesspalace.tusky.util.DownsizeImageTask;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
import com.keylesspalace.tusky.util.ListUtils;
|
import com.keylesspalace.tusky.util.ListUtils;
|
||||||
import com.keylesspalace.tusky.util.SaveTootHelper;
|
import com.keylesspalace.tusky.util.SaveTootHelper;
|
||||||
import com.keylesspalace.tusky.util.SpanUtilsKt;
|
import com.keylesspalace.tusky.util.SpanUtilsKt;
|
||||||
|
@ -303,14 +286,20 @@ public final class ComposeActivity
|
||||||
if (activeAccount != null) {
|
if (activeAccount != null) {
|
||||||
ImageView composeAvatar = findViewById(R.id.composeAvatar);
|
ImageView composeAvatar = findViewById(R.id.composeAvatar);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(activeAccount.getProfilePictureUrl())) {
|
|
||||||
composeAvatar.setImageResource(R.drawable.avatar_default);
|
int[] actionBarSizeAttr = new int[] { R.attr.actionBarSize };
|
||||||
} else {
|
TypedArray a = obtainStyledAttributes(null, actionBarSizeAttr);
|
||||||
Glide.with(this).load(activeAccount.getProfilePictureUrl())
|
int avatarSize = a.getDimensionPixelSize(0, 1);
|
||||||
.error(R.drawable.avatar_default)
|
a.recycle();
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(composeAvatar);
|
boolean animateAvatars = preferences.getBoolean("animateGifAvatars", false);
|
||||||
}
|
|
||||||
|
ImageLoadingHelper.loadAvatar(
|
||||||
|
activeAccount.getProfilePictureUrl(),
|
||||||
|
composeAvatar,
|
||||||
|
avatarSize / 8,
|
||||||
|
animateAvatars
|
||||||
|
);
|
||||||
|
|
||||||
composeAvatar.setContentDescription(
|
composeAvatar.setContentDescription(
|
||||||
getString(R.string.compose_active_account_description,
|
getString(R.string.compose_active_account_description,
|
||||||
|
|
|
@ -35,6 +35,8 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.FitCenter
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
import com.keylesspalace.tusky.adapter.AccountFieldEditAdapter
|
import com.keylesspalace.tusky.adapter.AccountFieldEditAdapter
|
||||||
import com.keylesspalace.tusky.di.Injectable
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||||
|
@ -136,6 +138,10 @@ class EditProfileActivity : BaseActivity(), Injectable {
|
||||||
Glide.with(this)
|
Glide.with(this)
|
||||||
.load(me.avatar)
|
.load(me.avatar)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
|
.transform(
|
||||||
|
FitCenter(),
|
||||||
|
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_80dp))
|
||||||
|
)
|
||||||
.into(avatarPreview)
|
.into(avatarPreview)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,8 +164,8 @@ class EditProfileActivity : BaseActivity(), Injectable {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
observeImage(viewModel.avatarData, avatarPreview, avatarProgressBar)
|
observeImage(viewModel.avatarData, avatarPreview, avatarProgressBar, true)
|
||||||
observeImage(viewModel.headerData, headerPreview, headerProgressBar)
|
observeImage(viewModel.headerData, headerPreview, headerProgressBar, false)
|
||||||
|
|
||||||
viewModel.saveData.observe(this, Observer<Resource<Nothing>> {
|
viewModel.saveData.observe(this, Observer<Resource<Nothing>> {
|
||||||
when(it) {
|
when(it) {
|
||||||
|
@ -192,12 +198,26 @@ class EditProfileActivity : BaseActivity(), Injectable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeImage(liveData: LiveData<Resource<Bitmap>>, imageView: ImageView, progressBar: View) {
|
private fun observeImage(liveData: LiveData<Resource<Bitmap>>,
|
||||||
|
imageView: ImageView,
|
||||||
|
progressBar: View,
|
||||||
|
roundedCorners: Boolean) {
|
||||||
liveData.observe(this, Observer<Resource<Bitmap>> {
|
liveData.observe(this, Observer<Resource<Bitmap>> {
|
||||||
|
|
||||||
when (it) {
|
when (it) {
|
||||||
is Success -> {
|
is Success -> {
|
||||||
imageView.setImageBitmap(it.data)
|
val glide = Glide.with(imageView)
|
||||||
|
.load(it.data)
|
||||||
|
|
||||||
|
if (roundedCorners) {
|
||||||
|
glide.transform(
|
||||||
|
FitCenter(),
|
||||||
|
RoundedCorners(resources.getDimensionPixelSize(R.dimen.avatar_radius_80dp))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
glide.into(imageView)
|
||||||
|
|
||||||
imageView.show()
|
imageView.show()
|
||||||
progressBar.hide()
|
progressBar.hide()
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ import androidx.viewpager.widget.ViewPager;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
@ -78,9 +79,6 @@ import dagger.android.AndroidInjector;
|
||||||
import dagger.android.DispatchingAndroidInjector;
|
import dagger.android.DispatchingAndroidInjector;
|
||||||
import dagger.android.support.HasSupportFragmentInjector;
|
import dagger.android.support.HasSupportFragmentInjector;
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import retrofit2.Call;
|
|
||||||
import retrofit2.Callback;
|
|
||||||
import retrofit2.Response;
|
|
||||||
|
|
||||||
import static com.keylesspalace.tusky.util.MediaUtilsKt.deleteStaleCachedMedia;
|
import static com.keylesspalace.tusky.util.MediaUtilsKt.deleteStaleCachedMedia;
|
||||||
import static com.uber.autodispose.AutoDispose.autoDisposable;
|
import static com.uber.autodispose.AutoDispose.autoDisposable;
|
||||||
|
@ -330,9 +328,18 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
||||||
background.setColorFilter(ContextCompat.getColor(this, R.color.header_background_filter));
|
background.setColorFilter(ContextCompat.getColor(this, R.color.header_background_filter));
|
||||||
background.setBackgroundColor(ContextCompat.getColor(this, R.color.window_background_dark));
|
background.setBackgroundColor(ContextCompat.getColor(this, R.color.window_background_dark));
|
||||||
|
|
||||||
|
final boolean animateAvatars = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
.getBoolean("animateGifAvatars", false);
|
||||||
|
|
||||||
DrawerImageLoader.init(new AbstractDrawerImageLoader() {
|
DrawerImageLoader.init(new AbstractDrawerImageLoader() {
|
||||||
@Override
|
@Override
|
||||||
public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) {
|
public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) {
|
||||||
|
if(animateAvatars) {
|
||||||
|
Glide.with(MainActivity.this)
|
||||||
|
.load(uri)
|
||||||
|
.placeholder(placeholder)
|
||||||
|
.into(imageView);
|
||||||
|
} else {
|
||||||
Glide.with(MainActivity.this)
|
Glide.with(MainActivity.this)
|
||||||
.asBitmap()
|
.asBitmap()
|
||||||
.load(uri)
|
.load(uri)
|
||||||
|
@ -340,6 +347,8 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
||||||
.into(imageView);
|
.into(imageView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel(ImageView imageView) {
|
public void cancel(ImageView imageView) {
|
||||||
Glide.with(MainActivity.this).clear(imageView);
|
Glide.with(MainActivity.this).clear(imageView);
|
||||||
|
|
|
@ -137,13 +137,7 @@ class PreferencesActivity : BaseActivity(), SharedPreferences.OnSharedPreference
|
||||||
}
|
}
|
||||||
//workaround end
|
//workaround end
|
||||||
}
|
}
|
||||||
"statusTextSize" -> {
|
"statusTextSize", "absoluteTimeView", "showBotOverlay", "animateGifAvatars" -> {
|
||||||
restartActivitiesOnExit = true
|
|
||||||
}
|
|
||||||
"absoluteTimeView" -> {
|
|
||||||
restartActivitiesOnExit = true
|
|
||||||
}
|
|
||||||
"showBotOverlay" -> {
|
|
||||||
restartActivitiesOnExit = true
|
restartActivitiesOnExit = true
|
||||||
}
|
}
|
||||||
"language" -> {
|
"language" -> {
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
package com.keylesspalace.tusky.adapter
|
package com.keylesspalace.tusky.adapter
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
import android.preference.PreferenceManager
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import com.bumptech.glide.Glide
|
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.db.AccountEntity
|
import com.keylesspalace.tusky.db.AccountEntity
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||||
|
import com.keylesspalace.tusky.util.loadAvatar
|
||||||
|
|
||||||
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
||||||
|
|
||||||
class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) {
|
class AccountSelectionAdapter(context: Context) : ArrayAdapter<AccountEntity>(context, R.layout.item_autocomplete_account) {
|
||||||
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
|
||||||
var view = convertView
|
var view = convertView
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(con
|
||||||
val avatar = view.avatar
|
val avatar = view.avatar
|
||||||
username.text = account.fullName
|
username.text = account.fullName
|
||||||
displayName.text = CustomEmojiHelper.emojifyString(account.displayName, account.emojis, displayName)
|
displayName.text = CustomEmojiHelper.emojifyString(account.displayName, account.emojis, displayName)
|
||||||
if (!TextUtils.isEmpty(account.profilePictureUrl)) {
|
|
||||||
Glide.with(avatar)
|
val avatarRadius = avatar.context.resources.getDimensionPixelSize(R.dimen.avatar_radius_42dp)
|
||||||
.asBitmap()
|
val animateAvatar = PreferenceManager.getDefaultSharedPreferences(avatar.context)
|
||||||
.load(account.profilePictureUrl)
|
.getBoolean("animateGifAvatars", false)
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar)
|
loadAvatar(account.profilePictureUrl, avatar, avatarRadius, animateAvatar)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
|
|
@ -2,17 +2,18 @@ package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
|
|
||||||
class AccountViewHolder extends RecyclerView.ViewHolder {
|
class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
private TextView username;
|
private TextView username;
|
||||||
|
@ -21,6 +22,7 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
private ImageView avatarInset;
|
private ImageView avatarInset;
|
||||||
private String accountId;
|
private String accountId;
|
||||||
private boolean showBotOverlay;
|
private boolean showBotOverlay;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
AccountViewHolder(View itemView) {
|
AccountViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -28,7 +30,9 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
displayName = itemView.findViewById(R.id.account_display_name);
|
displayName = itemView.findViewById(R.id.account_display_name);
|
||||||
avatar = itemView.findViewById(R.id.account_avatar);
|
avatar = itemView.findViewById(R.id.account_avatar);
|
||||||
avatarInset = itemView.findViewById(R.id.account_avatar_inset);
|
avatarInset = itemView.findViewById(R.id.account_avatar_inset);
|
||||||
showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true);
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(itemView.getContext());
|
||||||
|
showBotOverlay = sharedPrefs.getBoolean("showBotOverlay", true);
|
||||||
|
animateAvatar = sharedPrefs.getBoolean("animateGifAvatars", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -38,11 +42,9 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
username.setText(formattedUsername);
|
username.setText(formattedUsername);
|
||||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(), account.getEmojis(), displayName);
|
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(), account.getEmojis(), displayName);
|
||||||
displayName.setText(emojifiedName);
|
displayName.setText(emojifiedName);
|
||||||
Glide.with(avatar)
|
int avatarRadius = avatar.getContext().getResources()
|
||||||
.asBitmap()
|
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
.load(account.getAvatar())
|
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
if (showBotOverlay && account.getBot()) {
|
if (showBotOverlay && account.getBot()) {
|
||||||
avatarInset.setVisibility(View.VISIBLE);
|
avatarInset.setVisibility(View.VISIBLE);
|
||||||
avatarInset.setImageResource(R.drawable.ic_bot_24dp);
|
avatarInset.setImageResource(R.drawable.ic_bot_24dp);
|
||||||
|
|
|
@ -17,6 +17,8 @@ package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -24,11 +26,11 @@ import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
|
|
||||||
public class BlocksAdapter extends AccountAdapter {
|
public class BlocksAdapter extends AccountAdapter {
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ public class BlocksAdapter extends AccountAdapter {
|
||||||
private TextView displayName;
|
private TextView displayName;
|
||||||
private ImageButton unblock;
|
private ImageButton unblock;
|
||||||
private String id;
|
private String id;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
BlockedUserViewHolder(View itemView) {
|
BlockedUserViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -76,6 +79,9 @@ public class BlocksAdapter extends AccountAdapter {
|
||||||
username = itemView.findViewById(R.id.blocked_user_username);
|
username = itemView.findViewById(R.id.blocked_user_username);
|
||||||
displayName = itemView.findViewById(R.id.blocked_user_display_name);
|
displayName = itemView.findViewById(R.id.blocked_user_display_name);
|
||||||
unblock = itemView.findViewById(R.id.blocked_user_unblock);
|
unblock = itemView.findViewById(R.id.blocked_user_unblock);
|
||||||
|
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||||
|
.getBoolean("animateGifAvatars", false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -85,11 +91,9 @@ public class BlocksAdapter extends AccountAdapter {
|
||||||
String format = username.getContext().getString(R.string.status_username_format);
|
String format = username.getContext().getString(R.string.status_username_format);
|
||||||
String formattedUsername = String.format(format, account.getUsername());
|
String formattedUsername = String.format(format, account.getUsername());
|
||||||
username.setText(formattedUsername);
|
username.setText(formattedUsername);
|
||||||
Glide.with(avatar)
|
int avatarRadius = avatar.getContext().getResources()
|
||||||
.asBitmap()
|
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
.load(account.getAvatar())
|
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener) {
|
void setupActionListener(final AccountActionListener listener) {
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
package com.keylesspalace.tusky.adapter;
|
package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -30,6 +31,7 @@ import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -146,13 +148,19 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
||||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(),
|
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(),
|
||||||
account.getEmojis(), accountViewHolder.displayName);
|
account.getEmojis(), accountViewHolder.displayName);
|
||||||
accountViewHolder.displayName.setText(emojifiedName);
|
accountViewHolder.displayName.setText(emojifiedName);
|
||||||
if (!account.getAvatar().isEmpty()) {
|
|
||||||
Glide.with(accountViewHolder.avatar)
|
int avatarRadius = accountViewHolder.avatar.getContext().getResources()
|
||||||
.asBitmap()
|
.getDimensionPixelSize(R.dimen.avatar_radius_42dp);
|
||||||
.load(account.getAvatar())
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
boolean animateAvatar = PreferenceManager.getDefaultSharedPreferences(accountViewHolder.avatar.getContext())
|
||||||
.into(accountViewHolder.avatar);
|
.getBoolean("animateGifAvatars", false);
|
||||||
}
|
|
||||||
|
ImageLoadingHelper.loadAvatar(
|
||||||
|
account.getAvatar(),
|
||||||
|
accountViewHolder.avatar,
|
||||||
|
avatarRadius,
|
||||||
|
animateAvatar
|
||||||
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -24,11 +26,11 @@ import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
|
|
||||||
public class FollowRequestsAdapter extends AccountAdapter {
|
public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
|
|
||||||
|
@ -70,6 +72,7 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
private ImageButton accept;
|
private ImageButton accept;
|
||||||
private ImageButton reject;
|
private ImageButton reject;
|
||||||
private String id;
|
private String id;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
FollowRequestViewHolder(View itemView) {
|
FollowRequestViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -78,6 +81,8 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
displayName = itemView.findViewById(R.id.displayNameTextView);
|
displayName = itemView.findViewById(R.id.displayNameTextView);
|
||||||
accept = itemView.findViewById(R.id.acceptButton);
|
accept = itemView.findViewById(R.id.acceptButton);
|
||||||
reject = itemView.findViewById(R.id.rejectButton);
|
reject = itemView.findViewById(R.id.rejectButton);
|
||||||
|
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||||
|
.getBoolean("animateGifAvatars", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -87,11 +92,9 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
||||||
String format = username.getContext().getString(R.string.status_username_format);
|
String format = username.getContext().getString(R.string.status_username_format);
|
||||||
String formattedUsername = String.format(format, account.getUsername());
|
String formattedUsername = String.format(format, account.getUsername());
|
||||||
username.setText(formattedUsername);
|
username.setText(formattedUsername);
|
||||||
Glide.with(avatar)
|
int avatarRadius = avatar.getContext().getResources()
|
||||||
.asBitmap()
|
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
.load(account.getAvatar())
|
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener) {
|
void setupActionListener(final AccountActionListener listener) {
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
@ -9,11 +11,11 @@ import android.widget.ImageButton;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
|
|
||||||
public class MutesAdapter extends AccountAdapter {
|
public class MutesAdapter extends AccountAdapter {
|
||||||
|
|
||||||
|
@ -55,6 +57,7 @@ public class MutesAdapter extends AccountAdapter {
|
||||||
private TextView displayName;
|
private TextView displayName;
|
||||||
private ImageButton unmute;
|
private ImageButton unmute;
|
||||||
private String id;
|
private String id;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
MutedUserViewHolder(View itemView) {
|
MutedUserViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -62,6 +65,8 @@ public class MutesAdapter extends AccountAdapter {
|
||||||
username = itemView.findViewById(R.id.muted_user_username);
|
username = itemView.findViewById(R.id.muted_user_username);
|
||||||
displayName = itemView.findViewById(R.id.muted_user_display_name);
|
displayName = itemView.findViewById(R.id.muted_user_display_name);
|
||||||
unmute = itemView.findViewById(R.id.muted_user_unmute);
|
unmute = itemView.findViewById(R.id.muted_user_unmute);
|
||||||
|
animateAvatar = PreferenceManager.getDefaultSharedPreferences(itemView.getContext())
|
||||||
|
.getBoolean("animateGifAvatars", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupWithAccount(Account account) {
|
void setupWithAccount(Account account) {
|
||||||
|
@ -71,11 +76,9 @@ public class MutesAdapter extends AccountAdapter {
|
||||||
String format = username.getContext().getString(R.string.status_username_format);
|
String format = username.getContext().getString(R.string.status_username_format);
|
||||||
String formattedUsername = String.format(format, account.getUsername());
|
String formattedUsername = String.format(format, account.getUsername());
|
||||||
username.setText(formattedUsername);
|
username.setText(formattedUsername);
|
||||||
Glide.with(avatar)
|
int avatarRadius = avatar.getContext().getResources()
|
||||||
.asBitmap()
|
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
.load(account.getAvatar())
|
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupActionListener(final AccountActionListener listener) {
|
void setupActionListener(final AccountActionListener listener) {
|
||||||
|
|
|
@ -33,7 +33,6 @@ import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.ToggleButton;
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Account;
|
import com.keylesspalace.tusky.entity.Account;
|
||||||
import com.keylesspalace.tusky.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
|
@ -42,6 +41,7 @@ import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
import com.keylesspalace.tusky.util.DateUtils;
|
import com.keylesspalace.tusky.util.DateUtils;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||||
|
@ -82,6 +82,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
private NotificationActionListener notificationActionListener;
|
private NotificationActionListener notificationActionListener;
|
||||||
private boolean mediaPreviewEnabled;
|
private boolean mediaPreviewEnabled;
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
|
private boolean showBotOverlay;
|
||||||
|
private boolean animateAvatar;
|
||||||
private BidiFormatter bidiFormatter;
|
private BidiFormatter bidiFormatter;
|
||||||
private AdapterDataSource<NotificationViewData> dataSource;
|
private AdapterDataSource<NotificationViewData> dataSource;
|
||||||
|
|
||||||
|
@ -96,6 +98,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
this.notificationActionListener = notificationActionListener;
|
this.notificationActionListener = notificationActionListener;
|
||||||
mediaPreviewEnabled = true;
|
mediaPreviewEnabled = true;
|
||||||
useAbsoluteTime = false;
|
useAbsoluteTime = false;
|
||||||
|
showBotOverlay = true;
|
||||||
|
animateAvatar = false;
|
||||||
bidiFormatter = BidiFormatter.getInstance();
|
bidiFormatter = BidiFormatter.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,12 +116,12 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
case VIEW_TYPE_STATUS_NOTIFICATION: {
|
case VIEW_TYPE_STATUS_NOTIFICATION: {
|
||||||
View view = inflater
|
View view = inflater
|
||||||
.inflate(R.layout.item_status_notification, parent, false);
|
.inflate(R.layout.item_status_notification, parent, false);
|
||||||
return new StatusNotificationViewHolder(view, useAbsoluteTime);
|
return new StatusNotificationViewHolder(view, useAbsoluteTime, animateAvatar);
|
||||||
}
|
}
|
||||||
case VIEW_TYPE_FOLLOW: {
|
case VIEW_TYPE_FOLLOW: {
|
||||||
View view = inflater
|
View view = inflater
|
||||||
.inflate(R.layout.item_follow, parent, false);
|
.inflate(R.layout.item_follow, parent, false);
|
||||||
return new FollowViewHolder(view);
|
return new FollowViewHolder(view, animateAvatar);
|
||||||
}
|
}
|
||||||
case VIEW_TYPE_PLACEHOLDER: {
|
case VIEW_TYPE_PLACEHOLDER: {
|
||||||
View view = inflater
|
View view = inflater
|
||||||
|
@ -167,7 +171,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
StatusViewData.Concrete status = concreteNotificaton.getStatusViewData();
|
||||||
holder.setupWithStatus(status,
|
holder.setupWithStatus(status,
|
||||||
statusListener, mediaPreviewEnabled, payloadForHolder);
|
statusListener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloadForHolder);
|
||||||
if(concreteNotificaton.getType() == Notification.Type.POLL) {
|
if(concreteNotificaton.getType() == Notification.Type.POLL) {
|
||||||
holder.setPollInfo(accountId.equals(concreteNotificaton.getAccount().getId()));
|
holder.setPollInfo(accountId.equals(concreteNotificaton.getAccount().getId()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -266,6 +270,14 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
this.useAbsoluteTime = useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||||
|
this.showBotOverlay = showBotOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnimateAvatar(boolean animateAvatar) {
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
public interface NotificationActionListener {
|
public interface NotificationActionListener {
|
||||||
void onViewAccount(String id);
|
void onViewAccount(String id);
|
||||||
|
|
||||||
|
@ -288,13 +300,15 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
private TextView usernameView;
|
private TextView usernameView;
|
||||||
private TextView displayNameView;
|
private TextView displayNameView;
|
||||||
private ImageView avatar;
|
private ImageView avatar;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
FollowViewHolder(View itemView) {
|
FollowViewHolder(View itemView, boolean animateAvatar) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
message = itemView.findViewById(R.id.notification_text);
|
message = itemView.findViewById(R.id.notification_text);
|
||||||
usernameView = itemView.findViewById(R.id.notification_username);
|
usernameView = itemView.findViewById(R.id.notification_username);
|
||||||
displayNameView = itemView.findViewById(R.id.notification_display_name);
|
displayNameView = itemView.findViewById(R.id.notification_display_name);
|
||||||
avatar = itemView.findViewById(R.id.notification_avatar);
|
avatar = itemView.findViewById(R.id.notification_avatar);
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMessage(Account account, BidiFormatter bidiFormatter) {
|
void setMessage(Account account, BidiFormatter bidiFormatter) {
|
||||||
|
@ -313,15 +327,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
|
|
||||||
displayNameView.setText(emojifiedDisplayName);
|
displayNameView.setText(emojifiedDisplayName);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(account.getAvatar())) {
|
int avatarRadius = avatar.getContext().getResources()
|
||||||
avatar.setImageResource(R.drawable.avatar_default);
|
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||||
} else {
|
|
||||||
Glide.with(avatar)
|
ImageLoadingHelper.loadAvatar(account.getAvatar(), avatar, avatarRadius, animateAvatar);
|
||||||
.asBitmap()
|
|
||||||
.load(account.getAvatar())
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupButtons(final NotificationActionListener listener, final String accountId) {
|
void setupButtons(final NotificationActionListener listener, final String accountId) {
|
||||||
|
@ -349,10 +359,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
private StatusViewData.Concrete statusViewData;
|
private StatusViewData.Concrete statusViewData;
|
||||||
|
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
|
private boolean animateAvatar;
|
||||||
private SimpleDateFormat shortSdf;
|
private SimpleDateFormat shortSdf;
|
||||||
private SimpleDateFormat longSdf;
|
private SimpleDateFormat longSdf;
|
||||||
|
|
||||||
StatusNotificationViewHolder(View itemView, boolean useAbsoluteTime) {
|
StatusNotificationViewHolder(View itemView, boolean useAbsoluteTime, boolean animateAvatar) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
message = itemView.findViewById(R.id.notification_top_text);
|
message = itemView.findViewById(R.id.notification_top_text);
|
||||||
statusNameBar = itemView.findViewById(R.id.status_name_bar);
|
statusNameBar = itemView.findViewById(R.id.status_name_bar);
|
||||||
|
@ -376,6 +387,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
contentWarningButton.setOnCheckedChangeListener(this);
|
contentWarningButton.setOnCheckedChangeListener(this);
|
||||||
|
|
||||||
this.useAbsoluteTime = useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||||
}
|
}
|
||||||
|
@ -495,23 +507,17 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
|
|
||||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||||
|
|
||||||
if (TextUtils.isEmpty(statusAvatarUrl)) {
|
int statusAvatarRadius = statusAvatar.getContext().getResources()
|
||||||
statusAvatar.setImageResource(R.drawable.avatar_default);
|
.getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
} else {
|
|
||||||
Glide.with(statusAvatar)
|
|
||||||
.load(statusAvatarUrl)
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(statusAvatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(notificationAvatarUrl)) {
|
ImageLoadingHelper.loadAvatar(statusAvatarUrl,
|
||||||
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
statusAvatar, statusAvatarRadius, animateAvatar);
|
||||||
} else {
|
|
||||||
Glide.with(notificationAvatar)
|
int notificationAvatarRadius = statusAvatar.getContext().getResources()
|
||||||
.load(notificationAvatarUrl)
|
.getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(notificationAvatar);
|
ImageLoadingHelper.loadAvatar(notificationAvatarUrl,
|
||||||
}
|
notificationAvatar, notificationAvatarRadius, animateAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -49,15 +49,19 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
||||||
private boolean mediaPreviewsEnabled;
|
private boolean mediaPreviewsEnabled;
|
||||||
private boolean alwaysShowSensitiveMedia;
|
private boolean alwaysShowSensitiveMedia;
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
|
private boolean showBotOverlay;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
private LinkListener linkListener;
|
private LinkListener linkListener;
|
||||||
private StatusActionListener statusListener;
|
private StatusActionListener statusListener;
|
||||||
|
|
||||||
public SearchResultsAdapter(boolean mediaPreviewsEnabled,
|
public SearchResultsAdapter(LinkListener linkListener,
|
||||||
boolean alwaysShowSensitiveMedia,
|
|
||||||
LinkListener linkListener,
|
|
||||||
StatusActionListener statusListener,
|
StatusActionListener statusListener,
|
||||||
boolean useAbsoluteTime) {
|
boolean mediaPreviewsEnabled,
|
||||||
|
boolean alwaysShowSensitiveMedia,
|
||||||
|
boolean useAbsoluteTime,
|
||||||
|
boolean showBotOverlay,
|
||||||
|
boolean animateAvatar) {
|
||||||
|
|
||||||
this.accountList = Collections.emptyList();
|
this.accountList = Collections.emptyList();
|
||||||
this.statusList = Collections.emptyList();
|
this.statusList = Collections.emptyList();
|
||||||
|
@ -67,6 +71,8 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
||||||
this.mediaPreviewsEnabled = mediaPreviewsEnabled;
|
this.mediaPreviewsEnabled = mediaPreviewsEnabled;
|
||||||
this.alwaysShowSensitiveMedia = alwaysShowSensitiveMedia;
|
this.alwaysShowSensitiveMedia = alwaysShowSensitiveMedia;
|
||||||
this.useAbsoluteTime = useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
|
this.showBotOverlay = showBotOverlay;
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
|
|
||||||
this.linkListener = linkListener;
|
this.linkListener = linkListener;
|
||||||
this.statusListener = statusListener;
|
this.statusListener = statusListener;
|
||||||
|
@ -106,7 +112,8 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
||||||
} else {
|
} else {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
int index = position - accountList.size();
|
int index = position - accountList.size();
|
||||||
holder.setupWithStatus(concreteStatusList.get(index), statusListener, mediaPreviewsEnabled);
|
holder.setupWithStatus(concreteStatusList.get(index), statusListener,
|
||||||
|
mediaPreviewsEnabled, showBotOverlay, animateAvatar);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AccountViewHolder holder = (AccountViewHolder) viewHolder;
|
AccountViewHolder holder = (AccountViewHolder) viewHolder;
|
||||||
|
@ -133,11 +140,11 @@ public class SearchResultsAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Status getStatusAtPosition(int position) {
|
@Nullable public Status getStatusAtPosition(int position) {
|
||||||
return statusList.get(position - accountList.size());
|
return statusList.get(position - accountList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable StatusViewData.Concrete getConcreteStatusAtPosition(int position) {
|
@Nullable public StatusViewData.Concrete getConcreteStatusAtPosition(int position) {
|
||||||
return concreteStatusList.get(position - accountList.size());
|
return concreteStatusList.get(position - accountList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package com.keylesspalace.tusky.adapter;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.preference.PreferenceManager;
|
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
@ -16,6 +15,13 @@ import android.widget.RadioGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.ToggleButton;
|
import android.widget.ToggleButton;
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.emoji.text.EmojiCompat;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.bumptech.glide.Glide;
|
import com.bumptech.glide.Glide;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
|
@ -29,6 +35,7 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
import com.keylesspalace.tusky.util.DateUtils;
|
import com.keylesspalace.tusky.util.DateUtils;
|
||||||
import com.keylesspalace.tusky.util.HtmlUtils;
|
import com.keylesspalace.tusky.util.HtmlUtils;
|
||||||
|
import com.keylesspalace.tusky.util.ImageLoadingHelper;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.util.ThemeUtils;
|
import com.keylesspalace.tusky.util.ThemeUtils;
|
||||||
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
||||||
|
@ -43,12 +50,6 @@ import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
|
||||||
import androidx.emoji.text.EmojiCompat;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
import at.connyduck.sparkbutton.SparkButton;
|
import at.connyduck.sparkbutton.SparkButton;
|
||||||
import at.connyduck.sparkbutton.SparkEventListener;
|
import at.connyduck.sparkbutton.SparkEventListener;
|
||||||
import kotlin.collections.CollectionsKt;
|
import kotlin.collections.CollectionsKt;
|
||||||
|
@ -89,11 +90,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
private SimpleDateFormat shortSdf;
|
private SimpleDateFormat shortSdf;
|
||||||
private SimpleDateFormat longSdf;
|
private SimpleDateFormat longSdf;
|
||||||
private boolean showBotOverlay;
|
|
||||||
|
|
||||||
private final NumberFormat numberFormat = NumberFormat.getNumberInstance();
|
private final NumberFormat numberFormat = NumberFormat.getNumberInstance();
|
||||||
|
|
||||||
protected StatusBaseViewHolder(View itemView, boolean useAbsoluteTime) {
|
private int avatarRadius48dp;
|
||||||
|
private int avatarRadius36dp;
|
||||||
|
private int avatarRadius24dp;
|
||||||
|
|
||||||
|
protected StatusBaseViewHolder(View itemView,
|
||||||
|
boolean useAbsoluteTime) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
displayName = itemView.findViewById(R.id.status_display_name);
|
displayName = itemView.findViewById(R.id.status_display_name);
|
||||||
username = itemView.findViewById(R.id.status_username);
|
username = itemView.findViewById(R.id.status_username);
|
||||||
|
@ -104,8 +109,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
reblogButton = itemView.findViewById(R.id.status_inset);
|
reblogButton = itemView.findViewById(R.id.status_inset);
|
||||||
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
||||||
moreButton = itemView.findViewById(R.id.status_more);
|
moreButton = itemView.findViewById(R.id.status_more);
|
||||||
reblogged = false;
|
|
||||||
favourited = false;
|
|
||||||
mediaPreviews = new MediaPreviewImageView[]{
|
mediaPreviews = new MediaPreviewImageView[]{
|
||||||
itemView.findViewById(R.id.status_media_preview_0),
|
itemView.findViewById(R.id.status_media_preview_0),
|
||||||
itemView.findViewById(R.id.status_media_preview_1),
|
itemView.findViewById(R.id.status_media_preview_1),
|
||||||
|
@ -153,7 +157,10 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
this.useAbsoluteTime = useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
shortSdf = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
|
||||||
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
longSdf = new SimpleDateFormat("MM/dd HH:mm:ss", Locale.getDefault());
|
||||||
showBotOverlay = PreferenceManager.getDefaultSharedPreferences(itemView.getContext()).getBoolean("showBotOverlay", true);
|
|
||||||
|
this.avatarRadius48dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_48dp);
|
||||||
|
this.avatarRadius36dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_36dp);
|
||||||
|
this.avatarRadius24dp = itemView.getContext().getResources().getDimensionPixelSize(R.dimen.avatar_radius_24dp);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract int getMediaPreviewHeight(Context context);
|
protected abstract int getMediaPreviewHeight(Context context);
|
||||||
|
@ -219,8 +226,13 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setAvatar(String url, @Nullable String rebloggedUrl, boolean isBot) {
|
private void setAvatar(String url,
|
||||||
|
@Nullable String rebloggedUrl,
|
||||||
|
boolean isBot,
|
||||||
|
boolean showBotOverlay,
|
||||||
|
boolean animateAvatar) {
|
||||||
|
|
||||||
|
int avatarRadius;
|
||||||
if(TextUtils.isEmpty(rebloggedUrl)) {
|
if(TextUtils.isEmpty(rebloggedUrl)) {
|
||||||
avatar.setPaddingRelative(0, 0, 0, 0);
|
avatar.setPaddingRelative(0, 0, 0, 0);
|
||||||
|
|
||||||
|
@ -235,28 +247,20 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
avatarInset.setVisibility(View.GONE);
|
avatarInset.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
avatarRadius = avatarRadius48dp;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
int padding = Utils.convertDpToPx(avatar.getContext(), 12);
|
int padding = Utils.convertDpToPx(avatar.getContext(), 12);
|
||||||
avatar.setPaddingRelative(0, 0, padding, padding);
|
avatar.setPaddingRelative(0, 0, padding, padding);
|
||||||
|
|
||||||
avatarInset.setVisibility(View.VISIBLE);
|
avatarInset.setVisibility(View.VISIBLE);
|
||||||
avatarInset.setBackground(null);
|
avatarInset.setBackground(null);
|
||||||
Glide.with(avatarInset)
|
ImageLoadingHelper.loadAvatar(rebloggedUrl, avatarInset, avatarRadius24dp, animateAvatar);
|
||||||
.asBitmap()
|
|
||||||
.load(rebloggedUrl)
|
avatarRadius = avatarRadius36dp;
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatarInset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextUtils.isEmpty(url)) {
|
ImageLoadingHelper.loadAvatar(url, avatar, avatarRadius, animateAvatar);
|
||||||
avatar.setImageResource(R.drawable.avatar_default);
|
|
||||||
} else {
|
|
||||||
Glide.with(avatar)
|
|
||||||
.asBitmap()
|
|
||||||
.load(url)
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
|
||||||
.into(avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,18 +614,22 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled) {
|
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar) {
|
||||||
this.setupWithStatus(status, listener, mediaPreviewEnabled, null);
|
this.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
protected void setupWithStatus(StatusViewData.Concrete status,
|
||||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
final StatusActionListener listener,
|
||||||
|
boolean mediaPreviewEnabled,
|
||||||
|
boolean showBotOverlay,
|
||||||
|
boolean animateAvatar,
|
||||||
|
@Nullable Object payloads) {
|
||||||
if (payloads == null) {
|
if (payloads == null) {
|
||||||
setDisplayName(status.getUserFullName(), status.getAccountEmojis());
|
setDisplayName(status.getUserFullName(), status.getAccountEmojis());
|
||||||
setUsername(status.getNickname());
|
setUsername(status.getNickname());
|
||||||
setCreatedAt(status.getCreatedAt());
|
setCreatedAt(status.getCreatedAt());
|
||||||
setIsReply(status.getInReplyToId() != null);
|
setIsReply(status.getInReplyToId() != null);
|
||||||
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot());
|
setAvatar(status.getAvatar(), status.getRebloggedAvatar(), status.isBot(), showBotOverlay, animateAvatar);
|
||||||
setReblogged(status.isReblogged());
|
setReblogged(status.isReblogged());
|
||||||
setFavourited(status.isFavourited());
|
setFavourited(status.isFavourited());
|
||||||
List<Attachment> attachments = status.getAttachments();
|
List<Attachment> attachments = status.getAttachments();
|
||||||
|
|
|
@ -125,8 +125,9 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
@Nullable Object payloads) {
|
||||||
|
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||||
if (payloads == null) {
|
if (payloads == null) {
|
||||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||||
|
|
||||||
|
|
|
@ -51,14 +51,15 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
protected void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
boolean mediaPreviewEnabled, @Nullable Object payloads) {
|
boolean mediaPreviewEnabled, boolean showBotOverlay, boolean animateAvatar,
|
||||||
|
@Nullable Object payloads) {
|
||||||
if (status == null || payloads == null) {
|
if (status == null || payloads == null) {
|
||||||
if (status == null) {
|
if (status == null) {
|
||||||
showContent(false);
|
showContent(false);
|
||||||
} else {
|
} else {
|
||||||
showContent(true);
|
showContent(true);
|
||||||
setupCollapsedState(status, listener);
|
setupCollapsedState(status, listener);
|
||||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, null);
|
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, null);
|
||||||
|
|
||||||
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
String rebloggedByDisplayName = status.getRebloggedByUsername();
|
||||||
if (rebloggedByDisplayName == null) {
|
if (rebloggedByDisplayName == null) {
|
||||||
|
@ -70,7 +71,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
super.setupWithStatus(status, listener, mediaPreviewEnabled, payloads);
|
super.setupWithStatus(status, listener, mediaPreviewEnabled, showBotOverlay, animateAvatar, payloads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,8 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
private StatusActionListener statusActionListener;
|
private StatusActionListener statusActionListener;
|
||||||
private boolean mediaPreviewEnabled;
|
private boolean mediaPreviewEnabled;
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
|
private boolean showBotOverlay;
|
||||||
|
private boolean animateAvatar;
|
||||||
private int detailedStatusPosition;
|
private int detailedStatusPosition;
|
||||||
|
|
||||||
public ThreadAdapter(StatusActionListener listener) {
|
public ThreadAdapter(StatusActionListener listener) {
|
||||||
|
@ -44,6 +46,8 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
this.statuses = new ArrayList<>();
|
this.statuses = new ArrayList<>();
|
||||||
mediaPreviewEnabled = true;
|
mediaPreviewEnabled = true;
|
||||||
useAbsoluteTime = false;
|
useAbsoluteTime = false;
|
||||||
|
showBotOverlay = true;
|
||||||
|
animateAvatar = false;
|
||||||
detailedStatusPosition = RecyclerView.NO_POSITION;
|
detailedStatusPosition = RecyclerView.NO_POSITION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,10 +74,10 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
StatusViewData.Concrete status = statuses.get(position);
|
StatusViewData.Concrete status = statuses.get(position);
|
||||||
if (position == detailedStatusPosition) {
|
if (position == detailedStatusPosition) {
|
||||||
StatusDetailedViewHolder holder = (StatusDetailedViewHolder) viewHolder;
|
StatusDetailedViewHolder holder = (StatusDetailedViewHolder) viewHolder;
|
||||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||||
} else {
|
} else {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled);
|
holder.setupWithStatus(status, statusActionListener, mediaPreviewEnabled, showBotOverlay, animateAvatar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +159,14 @@ public class ThreadAdapter extends RecyclerView.Adapter {
|
||||||
this.useAbsoluteTime = useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||||
|
this.showBotOverlay = showBotOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnimateAvatar(boolean animateAvatar) {
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
public void setDetailedStatusPosition(int position) {
|
public void setDetailedStatusPosition(int position) {
|
||||||
if (position != detailedStatusPosition
|
if (position != detailedStatusPosition
|
||||||
&& detailedStatusPosition != RecyclerView.NO_POSITION) {
|
&& detailedStatusPosition != RecyclerView.NO_POSITION) {
|
||||||
|
|
|
@ -43,14 +43,17 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
private final StatusActionListener statusListener;
|
private final StatusActionListener statusListener;
|
||||||
private boolean mediaPreviewEnabled;
|
private boolean mediaPreviewEnabled;
|
||||||
private boolean useAbsoluteTime;
|
private boolean useAbsoluteTime;
|
||||||
|
private boolean showBotOverlay;
|
||||||
|
private boolean animateAvatar;
|
||||||
|
|
||||||
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
public TimelineAdapter(AdapterDataSource<StatusViewData> dataSource,
|
||||||
StatusActionListener statusListener) {
|
StatusActionListener statusListener) {
|
||||||
super();
|
|
||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.statusListener = statusListener;
|
this.statusListener = statusListener;
|
||||||
mediaPreviewEnabled = true;
|
mediaPreviewEnabled = true;
|
||||||
useAbsoluteTime = false;
|
useAbsoluteTime = false;
|
||||||
|
showBotOverlay = true;
|
||||||
|
animateAvatar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -89,7 +92,12 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
holder.setup(statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
holder.setup(statusListener, ((StatusViewData.Placeholder) status).isLoading());
|
||||||
} else if (status instanceof StatusViewData.Concrete) {
|
} else if (status instanceof StatusViewData.Concrete) {
|
||||||
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
StatusViewHolder holder = (StatusViewHolder) viewHolder;
|
||||||
holder.setupWithStatus((StatusViewData.Concrete)status,statusListener, mediaPreviewEnabled,payloads!=null&&!payloads.isEmpty()?payloads.get(0):null);
|
holder.setupWithStatus((StatusViewData.Concrete) status,
|
||||||
|
statusListener,
|
||||||
|
mediaPreviewEnabled,
|
||||||
|
showBotOverlay,
|
||||||
|
animateAvatar,
|
||||||
|
payloads != null && !payloads.isEmpty() ? payloads.get(0) : null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
|
@ -111,13 +119,21 @@ public final class TimelineAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUseAbsoluteTime(boolean useAbsoluteTime){
|
public void setUseAbsoluteTime(boolean useAbsoluteTime){
|
||||||
this.useAbsoluteTime=useAbsoluteTime;
|
this.useAbsoluteTime = useAbsoluteTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean getMediaPreviewEnabled() {
|
public boolean getMediaPreviewEnabled() {
|
||||||
return mediaPreviewEnabled;
|
return mediaPreviewEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setShowBotOverlay(boolean showBotOverlay) {
|
||||||
|
this.showBotOverlay = showBotOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAnimateAvatar(boolean animateAvatar) {
|
||||||
|
this.animateAvatar = animateAvatar;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
return dataSource.getItemAt(position).getViewDataId();
|
return dataSource.getItemAt(position).getViewDataId();
|
||||||
|
|
|
@ -230,6 +230,10 @@ public class NotificationsFragment extends SFragment implements
|
||||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||||
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
||||||
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
||||||
|
boolean showBotOverlay = preferences.getBoolean("showBotOverlay", true);
|
||||||
|
adapter.setShowBotOverlay(showBotOverlay);
|
||||||
|
boolean animateAvatar = preferences.getBoolean("animateGifAvatars", false);
|
||||||
|
adapter.setAnimateAvatar(animateAvatar);
|
||||||
recyclerView.setAdapter(adapter);
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
topLoading = false;
|
topLoading = false;
|
||||||
|
@ -734,7 +738,7 @@ public class NotificationsFragment extends SFragment implements
|
||||||
Log.w(TAG, "Didn't find a notification for ID: " + notificationId);
|
Log.w(TAG, "Didn't find a notification for ID: " + notificationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onPreferenceChanged(String key) {
|
private void onPreferenceChanged(String key) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "fabHide": {
|
case "fabHide": {
|
||||||
hideFab = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("fabHide", false);
|
hideFab = PreferenceManager.getDefaultSharedPreferences(getContext()).getBoolean("fabHide", false);
|
||||||
|
@ -746,7 +750,6 @@ public class NotificationsFragment extends SFragment implements
|
||||||
adapter.setMediaPreviewEnabled(enabled);
|
adapter.setMediaPreviewEnabled(enabled);
|
||||||
fullyRefresh();
|
fullyRefresh();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,8 +46,6 @@ class SearchFragment : SFragment(), StatusActionListener {
|
||||||
private lateinit var searchAdapter: SearchResultsAdapter
|
private lateinit var searchAdapter: SearchResultsAdapter
|
||||||
|
|
||||||
private var alwaysShowSensitiveMedia = false
|
private var alwaysShowSensitiveMedia = false
|
||||||
private var mediaPreviewEnabled = true
|
|
||||||
private var useAbsoluteTime = false
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_search, container, false)
|
return inflater.inflate(R.layout.fragment_search, container, false)
|
||||||
|
@ -55,20 +53,25 @@ class SearchFragment : SFragment(), StatusActionListener {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(view.context)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(view.context)
|
||||||
useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false)
|
val useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false)
|
||||||
|
val showBotOverlay = preferences.getBoolean("showBotOverlay", true)
|
||||||
|
val animateAvatar = preferences.getBoolean("animateGifAvatars", false)
|
||||||
|
|
||||||
val account = accountManager.activeAccount
|
val account = accountManager.activeAccount
|
||||||
alwaysShowSensitiveMedia = account?.alwaysShowSensitiveMedia ?: false
|
alwaysShowSensitiveMedia = account?.alwaysShowSensitiveMedia ?: false
|
||||||
mediaPreviewEnabled = account?.mediaPreviewEnabled ?: true
|
val mediaPreviewEnabled = account?.mediaPreviewEnabled ?: true
|
||||||
|
|
||||||
searchRecyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
searchRecyclerView.addItemDecoration(DividerItemDecoration(view.context, DividerItemDecoration.VERTICAL))
|
||||||
searchRecyclerView.layoutManager = LinearLayoutManager(view.context)
|
searchRecyclerView.layoutManager = LinearLayoutManager(view.context)
|
||||||
searchAdapter = SearchResultsAdapter(
|
searchAdapter = SearchResultsAdapter(
|
||||||
|
this,
|
||||||
|
this,
|
||||||
mediaPreviewEnabled,
|
mediaPreviewEnabled,
|
||||||
alwaysShowSensitiveMedia,
|
alwaysShowSensitiveMedia,
|
||||||
this,
|
useAbsoluteTime,
|
||||||
this,
|
showBotOverlay,
|
||||||
useAbsoluteTime)
|
animateAvatar
|
||||||
|
)
|
||||||
searchRecyclerView.adapter = searchAdapter
|
searchRecyclerView.adapter = searchAdapter
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,6 +354,10 @@ public class TimelineFragment extends SFragment implements
|
||||||
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
adapter.setMediaPreviewEnabled(mediaPreviewEnabled);
|
||||||
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
boolean useAbsoluteTime = preferences.getBoolean("absoluteTimeView", false);
|
||||||
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
adapter.setUseAbsoluteTime(useAbsoluteTime);
|
||||||
|
boolean showBotOverlay = preferences.getBoolean("showBotOverlay", true);
|
||||||
|
adapter.setShowBotOverlay(showBotOverlay);
|
||||||
|
boolean animateAvatar = preferences.getBoolean("animateGifAvatars", false);
|
||||||
|
adapter.setAnimateAvatar(animateAvatar);
|
||||||
|
|
||||||
boolean filter = preferences.getBoolean("tabFilterHomeReplies", true);
|
boolean filter = preferences.getBoolean("tabFilterHomeReplies", true);
|
||||||
filterRemoveReplies = kind == Kind.HOME && !filter;
|
filterRemoveReplies = kind == Kind.HOME && !filter;
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
@file:JvmName("ImageLoadingHelper")
|
||||||
|
|
||||||
|
package com.keylesspalace.tusky.util
|
||||||
|
|
||||||
|
import android.widget.ImageView
|
||||||
|
import androidx.annotation.Px
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.FitCenter
|
||||||
|
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
|
||||||
|
import com.keylesspalace.tusky.R
|
||||||
|
|
||||||
|
|
||||||
|
private val fitCenterTransformation = FitCenter()
|
||||||
|
|
||||||
|
fun loadAvatar(url: String?, imageView: ImageView, @Px radius: Int, animate: Boolean) {
|
||||||
|
|
||||||
|
if(url.isNullOrBlank()) {
|
||||||
|
Glide.with(imageView)
|
||||||
|
.load(R.drawable.avatar_default)
|
||||||
|
.into(imageView)
|
||||||
|
} else {
|
||||||
|
if (animate) {
|
||||||
|
Glide.with(imageView)
|
||||||
|
.load(url)
|
||||||
|
.transform(
|
||||||
|
fitCenterTransformation,
|
||||||
|
RoundedCorners(radius)
|
||||||
|
)
|
||||||
|
.into(imageView)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Glide.with(imageView)
|
||||||
|
.asBitmap()
|
||||||
|
.load(url)
|
||||||
|
.transform(
|
||||||
|
fitCenterTransformation,
|
||||||
|
RoundedCorners(radius)
|
||||||
|
)
|
||||||
|
.into(imageView)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,325 +0,0 @@
|
||||||
package com.keylesspalace.tusky.view;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Original CircleImageView Copyright 2014 - 2018 Henning Dodenhof
|
|
||||||
* Adapted to RoundedImageView by charlag in 2018
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.graphics.Bitmap;
|
|
||||||
import android.graphics.BitmapShader;
|
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.graphics.ColorFilter;
|
|
||||||
import android.graphics.Matrix;
|
|
||||||
import android.graphics.Outline;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.graphics.Shader;
|
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
|
||||||
import android.graphics.drawable.ColorDrawable;
|
|
||||||
import android.graphics.drawable.Drawable;
|
|
||||||
import android.net.Uri;
|
|
||||||
import androidx.annotation.DrawableRes;
|
|
||||||
import androidx.appcompat.widget.AppCompatImageView;
|
|
||||||
import android.util.AttributeSet;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewOutlineProvider;
|
|
||||||
|
|
||||||
public class RoundedImageView extends AppCompatImageView {
|
|
||||||
|
|
||||||
private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP;
|
|
||||||
|
|
||||||
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
|
|
||||||
private static final int COLORDRAWABLE_DIMENSION = 2;
|
|
||||||
|
|
||||||
private static final int DEFAULT_BORDER_WIDTH = 0;
|
|
||||||
private static final int DEFAULT_BORDER_COLOR = Color.BLACK;
|
|
||||||
private static final int DEFAULT_CIRCLE_BACKGROUND_COLOR = Color.TRANSPARENT;
|
|
||||||
private static float ROUNDED_PERCENT = 25;
|
|
||||||
|
|
||||||
private final RectF mDrawableRect = new RectF();
|
|
||||||
private final RectF mBorderRect = new RectF();
|
|
||||||
|
|
||||||
private final Matrix mShaderMatrix = new Matrix();
|
|
||||||
private final Paint mBitmapPaint = new Paint();
|
|
||||||
private final Paint mBorderPaint = new Paint();
|
|
||||||
private final Paint mCircleBackgroundPaint = new Paint();
|
|
||||||
|
|
||||||
private int mCircleBackgroundColor = DEFAULT_CIRCLE_BACKGROUND_COLOR;
|
|
||||||
|
|
||||||
private Bitmap mBitmap;
|
|
||||||
private BitmapShader mBitmapShader;
|
|
||||||
private int mBitmapWidth;
|
|
||||||
private int mBitmapHeight;
|
|
||||||
|
|
||||||
private float mDrawableRadius;
|
|
||||||
private float mBorderRadius;
|
|
||||||
|
|
||||||
private ColorFilter mColorFilter;
|
|
||||||
|
|
||||||
private boolean mReady;
|
|
||||||
private boolean mSetupPending;
|
|
||||||
|
|
||||||
public RoundedImageView(Context context) {
|
|
||||||
super(context);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoundedImageView(Context context, AttributeSet attrs) {
|
|
||||||
this(context, attrs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
|
|
||||||
super(context, attrs, defStyle);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
super.setScaleType(SCALE_TYPE);
|
|
||||||
mReady = true;
|
|
||||||
|
|
||||||
setOutlineProvider(new OutlineProvider());
|
|
||||||
|
|
||||||
if (mSetupPending) {
|
|
||||||
setup();
|
|
||||||
mSetupPending = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ScaleType getScaleType() {
|
|
||||||
return SCALE_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setScaleType(ScaleType scaleType) {
|
|
||||||
if (scaleType != SCALE_TYPE) {
|
|
||||||
throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAdjustViewBounds(boolean adjustViewBounds) {
|
|
||||||
if (adjustViewBounds) {
|
|
||||||
throw new IllegalArgumentException("adjustViewBounds not supported.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDraw(Canvas canvas) {
|
|
||||||
|
|
||||||
if (mBitmap == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mCircleBackgroundColor != Color.TRANSPARENT) {
|
|
||||||
canvas.drawRoundRect(mDrawableRect, mDrawableRadius, mDrawableRadius,
|
|
||||||
mCircleBackgroundPaint);
|
|
||||||
}
|
|
||||||
canvas.drawRoundRect(mDrawableRect, mDrawableRadius, mDrawableRadius, mBitmapPaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
|
|
||||||
super.onSizeChanged(w, h, oldw, oldh);
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPadding(int left, int top, int right, int bottom) {
|
|
||||||
super.setPadding(left, top, right, bottom);
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPaddingRelative(int start, int top, int end, int bottom) {
|
|
||||||
super.setPaddingRelative(start, top, end, bottom);
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImageBitmap(Bitmap bm) {
|
|
||||||
super.setImageBitmap(bm);
|
|
||||||
initializeBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImageDrawable(Drawable drawable) {
|
|
||||||
super.setImageDrawable(drawable);
|
|
||||||
initializeBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImageResource(@DrawableRes int resId) {
|
|
||||||
super.setImageResource(resId);
|
|
||||||
initializeBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setImageURI(Uri uri) {
|
|
||||||
super.setImageURI(uri);
|
|
||||||
initializeBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setColorFilter(ColorFilter cf) {
|
|
||||||
if (cf == mColorFilter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mColorFilter = cf;
|
|
||||||
applyColorFilter();
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ColorFilter getColorFilter() {
|
|
||||||
return mColorFilter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void applyColorFilter() {
|
|
||||||
mBitmapPaint.setColorFilter(mColorFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bitmap getBitmapFromDrawable(Drawable drawable) {
|
|
||||||
if (drawable == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (drawable instanceof BitmapDrawable) {
|
|
||||||
return ((BitmapDrawable) drawable).getBitmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Bitmap bitmap;
|
|
||||||
|
|
||||||
if (drawable instanceof ColorDrawable) {
|
|
||||||
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
|
|
||||||
} else {
|
|
||||||
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
|
||||||
drawable.draw(canvas);
|
|
||||||
return bitmap;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initializeBitmap() {
|
|
||||||
mBitmap = getBitmapFromDrawable(getDrawable());
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setup() {
|
|
||||||
if (!mReady) {
|
|
||||||
mSetupPending = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getWidth() == 0 && getHeight() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mBitmap == null) {
|
|
||||||
invalidate();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
|
|
||||||
|
|
||||||
mBitmapPaint.setAntiAlias(true);
|
|
||||||
mBitmapPaint.setShader(mBitmapShader);
|
|
||||||
|
|
||||||
mBorderPaint.setStyle(Paint.Style.STROKE);
|
|
||||||
mBorderPaint.setAntiAlias(true);
|
|
||||||
mBorderPaint.setColor(DEFAULT_BORDER_COLOR);
|
|
||||||
mBorderPaint.setStrokeWidth(DEFAULT_BORDER_WIDTH);
|
|
||||||
|
|
||||||
mCircleBackgroundPaint.setStyle(Paint.Style.FILL);
|
|
||||||
mCircleBackgroundPaint.setAntiAlias(true);
|
|
||||||
mCircleBackgroundPaint.setColor(mCircleBackgroundColor);
|
|
||||||
|
|
||||||
mBitmapHeight = mBitmap.getHeight();
|
|
||||||
mBitmapWidth = mBitmap.getWidth();
|
|
||||||
|
|
||||||
mBorderRect.set(calculateBounds());
|
|
||||||
|
|
||||||
float shorterSideBorder = Math.min(mBorderRect.width(), mBorderRect.height());
|
|
||||||
mBorderRadius = shorterSideBorder / 2 * ROUNDED_PERCENT / 100;
|
|
||||||
|
|
||||||
mDrawableRect.set(mBorderRect);
|
|
||||||
|
|
||||||
float shorterSide = Math.min(mDrawableRect.width(), mDrawableRect.height());
|
|
||||||
mDrawableRadius = shorterSide / 2 * ROUNDED_PERCENT / 100;
|
|
||||||
|
|
||||||
|
|
||||||
applyColorFilter();
|
|
||||||
updateShaderMatrix();
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
private RectF calculateBounds() {
|
|
||||||
int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight();
|
|
||||||
int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom();
|
|
||||||
|
|
||||||
int sideLength = Math.min(availableWidth, availableHeight);
|
|
||||||
|
|
||||||
float left = getPaddingLeft() + (availableWidth - sideLength) / 2f;
|
|
||||||
float top = getPaddingTop() + (availableHeight - sideLength) / 2f;
|
|
||||||
|
|
||||||
return new RectF(left, top, left + sideLength, top + sideLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateShaderMatrix() {
|
|
||||||
float scale;
|
|
||||||
float dx = 0;
|
|
||||||
float dy = 0;
|
|
||||||
|
|
||||||
mShaderMatrix.set(null);
|
|
||||||
|
|
||||||
if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
|
|
||||||
scale = mDrawableRect.height() / (float) mBitmapHeight;
|
|
||||||
dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f;
|
|
||||||
} else {
|
|
||||||
scale = mDrawableRect.width() / (float) mBitmapWidth;
|
|
||||||
dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f;
|
|
||||||
}
|
|
||||||
|
|
||||||
mShaderMatrix.setScale(scale, scale);
|
|
||||||
mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top);
|
|
||||||
|
|
||||||
mBitmapShader.setLocalMatrix(mShaderMatrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class OutlineProvider extends ViewOutlineProvider {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void getOutline(View view, Outline outline) {
|
|
||||||
Rect bounds = new Rect();
|
|
||||||
mBorderRect.roundOut(bounds);
|
|
||||||
outline.setRoundRect(bounds, mBorderRadius);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -352,7 +352,7 @@
|
||||||
|
|
||||||
<include layout="@layout/item_status_bottom_sheet" />
|
<include layout="@layout/item_status_bottom_sheet" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/accountAvatarImageView"
|
android:id="@+id/accountAvatarImageView"
|
||||||
android:layout_width="@dimen/account_activity_avatar_size"
|
android:layout_width="@dimen/account_activity_avatar_size"
|
||||||
android:layout_height="@dimen/account_activity_avatar_size"
|
android:layout_height="@dimen/account_activity_avatar_size"
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:background="@android:color/transparent">
|
android:background="@android:color/transparent">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/composeAvatar"
|
android:id="@+id/composeAvatar"
|
||||||
android:layout_width="?attr/actionBarSize"
|
android:layout_width="?attr/actionBarSize"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
|
|
@ -46,7 +46,7 @@
|
||||||
app:layout_constraintStart_toStartOf="@id/headerPreview"
|
app:layout_constraintStart_toStartOf="@id/headerPreview"
|
||||||
app:layout_constraintTop_toTopOf="@id/headerPreview" />
|
app:layout_constraintTop_toTopOf="@id/headerPreview" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/avatarPreview"
|
android:id="@+id/avatarPreview"
|
||||||
android:layout_width="80dp"
|
android:layout_width="80dp"
|
||||||
android:layout_height="80dp"
|
android:layout_height="80dp"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
android:paddingStart="16dp"
|
android:paddingStart="16dp"
|
||||||
android:paddingEnd="16dp">
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/account_avatar"
|
android:id="@+id/account_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/account_avatar_inset"
|
android:id="@+id/account_avatar_inset"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
android:padding="8dp">
|
android:padding="8dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/blocked_user_avatar"
|
android:id="@+id/blocked_user_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
tools:text="ConnyDuck boosted"
|
tools:text="ConnyDuck boosted"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar_2"
|
android:id="@+id/status_avatar_2"
|
||||||
android:layout_width="52dp"
|
android:layout_width="52dp"
|
||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
|
@ -42,7 +42,7 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/status_avatar_1"
|
app:layout_constraintTop_toTopOf="@id/status_avatar_1"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar_1"
|
android:id="@+id/status_avatar_1"
|
||||||
android:layout_width="52dp"
|
android:layout_width="52dp"
|
||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/status_avatar"
|
app:layout_constraintTop_toTopOf="@id/status_avatar"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar"
|
android:id="@+id/status_avatar"
|
||||||
android:layout_width="52dp"
|
android:layout_width="52dp"
|
||||||
android:layout_height="52dp"
|
android:layout_height="52dp"
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/conversation_name"
|
app:layout_constraintTop_toBottomOf="@id/conversation_name"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar_inset"
|
android:id="@+id/status_avatar_inset"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?><!--
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
* This is the for folnotificationsEnabledions, the layout for the follows/following listings on account
|
* This is the for follow notifications, the layout for the follows/following listings on account
|
||||||
* pages are instead in item_account.xml.
|
* pages are instead in item_account.xml.
|
||||||
-->
|
-->
|
||||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
android:textSize="?attr/status_text_medium"
|
android:textSize="?attr/status_text_medium"
|
||||||
tools:text="Someone followed you" />
|
tools:text="Someone followed you" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/notification_avatar"
|
android:id="@+id/notification_avatar"
|
||||||
android:layout_width="40dp"
|
android:layout_width="40dp"
|
||||||
android:layout_height="40dp"
|
android:layout_height="40dp"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/avatar"
|
android:id="@+id/avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
android:paddingLeft="16dp"
|
android:paddingLeft="16dp"
|
||||||
android:paddingRight="16dp">
|
android:paddingRight="16dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/muted_user_avatar"
|
android:id="@+id/muted_user_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
tools:text="ConnyDuck boosted"
|
tools:text="ConnyDuck boosted"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar"
|
android:id="@+id/status_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/status_info"
|
app:layout_constraintTop_toBottomOf="@id/status_info"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar_inset"
|
android:id="@+id/status_avatar_inset"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
android:paddingLeft="14dp"
|
android:paddingLeft="14dp"
|
||||||
android:paddingRight="14dp">
|
android:paddingRight="14dp">
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar"
|
android:id="@+id/status_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
@ -24,7 +24,7 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/status_avatar_inset"
|
android:id="@+id/status_avatar_inset"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
|
|
@ -137,7 +137,7 @@
|
||||||
android:textSize="?attr/status_text_medium"
|
android:textSize="?attr/status_text_medium"
|
||||||
android:visibility="gone" />
|
android:visibility="gone" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/notification_status_avatar"
|
android:id="@+id/notification_status_avatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
@ -153,7 +153,7 @@
|
||||||
tools:ignore="RtlHardcoded,RtlSymmetry"
|
tools:ignore="RtlHardcoded,RtlSymmetry"
|
||||||
tools:src="@drawable/avatar_default" />
|
tools:src="@drawable/avatar_default" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/notification_notification_avatar"
|
android:id="@+id/notification_notification_avatar"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Account has moved" />
|
tools:text="Account has moved" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.RoundedImageView
|
<ImageView
|
||||||
android:id="@+id/accountMovedAvatar"
|
android:id="@+id/accountMovedAvatar"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
android:layout_height="48dp"
|
android:layout_height="48dp"
|
||||||
|
|
|
@ -32,4 +32,12 @@
|
||||||
<dimen name="preference_icon_size">20dp</dimen>
|
<dimen name="preference_icon_size">20dp</dimen>
|
||||||
|
|
||||||
<dimen name="selected_drag_item_elevation">12dp</dimen>
|
<dimen name="selected_drag_item_elevation">12dp</dimen>
|
||||||
|
|
||||||
|
<dimen name="avatar_radius_94dp">11.75dp</dimen> <!-- 1/8 of 100dp - 2 * 3dp padding -->
|
||||||
|
<dimen name="avatar_radius_80dp">10dp</dimen> <!-- 1/8 of 80dp -->
|
||||||
|
<dimen name="avatar_radius_48dp">6dp</dimen> <!-- 1/8 of 48dp -->
|
||||||
|
<dimen name="avatar_radius_42dp">5.25dp</dimen> <!-- 1/8 of 42dp -->
|
||||||
|
<dimen name="avatar_radius_40dp">5dp</dimen> <!-- 1/8 of 40dp -->
|
||||||
|
<dimen name="avatar_radius_36dp">4.5dp</dimen> <!-- 1/8 of 36dp -->
|
||||||
|
<dimen name="avatar_radius_24dp">3dp</dimen> <!-- 1/8 of 24dp -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -216,6 +216,9 @@
|
||||||
<string name="pref_title_custom_tabs">Use Chrome Custom Tabs</string>
|
<string name="pref_title_custom_tabs">Use Chrome Custom Tabs</string>
|
||||||
<string name="pref_title_hide_follow_button">Hide compose button while scrolling</string>
|
<string name="pref_title_hide_follow_button">Hide compose button while scrolling</string>
|
||||||
<string name="pref_title_language">Language</string>
|
<string name="pref_title_language">Language</string>
|
||||||
|
<string name="pref_title_bot_overlay">Show indicator for bots</string>
|
||||||
|
<string name="pref_title_animate_gif_avatars">Animate GIF avatars</string>
|
||||||
|
|
||||||
<string name="pref_title_status_filter">Timeline filtering</string>
|
<string name="pref_title_status_filter">Timeline filtering</string>
|
||||||
<string name="pref_title_status_tabs">Tabs</string>
|
<string name="pref_title_status_tabs">Tabs</string>
|
||||||
<string name="pref_title_show_boosts">Show boosts</string>
|
<string name="pref_title_show_boosts">Show boosts</string>
|
||||||
|
@ -463,7 +466,6 @@
|
||||||
|
|
||||||
<string name="compose_shortcut_long_label">Compose Toot</string>
|
<string name="compose_shortcut_long_label">Compose Toot</string>
|
||||||
<string name="compose_shortcut_short_label">Compose</string>
|
<string name="compose_shortcut_short_label">Compose</string>
|
||||||
<string name="pref_title_bot_overlay">Show indicator for bots</string>
|
|
||||||
|
|
||||||
<string name="notification_clear_text">Are you sure you want to permanently clear all your notifications?</string>
|
<string name="notification_clear_text">Are you sure you want to permanently clear all your notifications?</string>
|
||||||
<string name="compose_preview_image_description">Actions for image %s</string>
|
<string name="compose_preview_image_description">Actions for image %s</string>
|
||||||
|
|
|
@ -49,6 +49,11 @@
|
||||||
android:defaultValue="true"
|
android:defaultValue="true"
|
||||||
android:key="showBotOverlay"
|
android:key="showBotOverlay"
|
||||||
android:title="@string/pref_title_bot_overlay" />
|
android:title="@string/pref_title_bot_overlay" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:defaultValue="false"
|
||||||
|
android:key="animateGifAvatars"
|
||||||
|
android:title="@string/pref_title_animate_gif_avatars" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/pref_title_browser_settings">
|
<PreferenceCategory android:title="@string/pref_title_browser_settings">
|
||||||
|
|
Loading…
Reference in a new issue