Migrate to Glide (#1175)
* Replace Picasso library with Glide library tuskyapp#1082 * Replace Picasso library with Glide library tuskyapp#1082 * Update load emoji with glide * Update context used for Glide * Removed unused import * Replace deprecated SimpleTarget with CustomTarget * Fix crash at the view image fragment, remove override image size * Replace Single.create with Single.fromCallable * View image fragment refactor * Fix after merge * Try to load cached image first and show progress view on failure * Try to load cached image first and show progress view on failure
This commit is contained in:
parent
cea879e841
commit
f7b577dfd1
|
@ -99,11 +99,9 @@ dependencies {
|
|||
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
|
||||
implementation 'com.squareup.picasso:picasso:2.5.2'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.14.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.0'
|
||||
implementation 'org.conscrypt:conscrypt-android:2.1.0'
|
||||
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
|
||||
implementation 'com.github.connyduck:sparkbutton:2.0.0'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||
implementation 'com.mikepenz:google-material-typeface:3.0.1.3.original@aar'
|
||||
|
@ -144,4 +142,9 @@ dependencies {
|
|||
implementation 'com.uber.autodispose:autodispose-android-archcomponents:1.2.0'
|
||||
implementation 'com.uber.autodispose:autodispose-ktx:1.2.0'
|
||||
implementation 'androidx.paging:paging-runtime-ktx:2.1.0'
|
||||
|
||||
//Glide
|
||||
implementation 'com.github.bumptech.glide:glide:4.9.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
|
||||
implementation 'com.github.bumptech.glide:okhttp3-integration:4.9.0'
|
||||
}
|
||||
|
|
|
@ -49,9 +49,6 @@
|
|||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||
|
||||
## for picasso
|
||||
-dontwarn com.squareup.okhttp.**
|
||||
|
||||
##for keep
|
||||
-dontwarn android.arch.util.paging.CountedDataSource
|
||||
-dontwarn android.arch.persistence.room.paging.LimitOffsetDataSource
|
||||
|
@ -100,3 +97,11 @@
|
|||
# work around a bug in proguard
|
||||
# see https://sourceforge.net/p/proguard/bugs/729/
|
||||
-keepnames public interface com.uber.autodispose.lifecycle.CorrespondingEventsFunction { *; }
|
||||
|
||||
# Glide
|
||||
-keep public class * implements com.bumptech.glide.module.GlideModule
|
||||
-keep public class * extends com.bumptech.glide.module.AppGlideModule
|
||||
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
|
||||
**[] $VALUES;
|
||||
public *;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProviders
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.bumptech.glide.Glide
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
|
@ -52,7 +53,6 @@ import com.keylesspalace.tusky.interfaces.ReselectableFragment
|
|||
import com.keylesspalace.tusky.pager.AccountPagerAdapter
|
||||
import com.keylesspalace.tusky.util.*
|
||||
import com.keylesspalace.tusky.viewmodel.AccountViewModel
|
||||
import com.squareup.picasso.Picasso
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DispatchingAndroidInjector
|
||||
import dagger.android.support.HasSupportFragmentInjector
|
||||
|
@ -321,13 +321,12 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
|||
accountLockedImageView.visible(account.locked)
|
||||
accountBadgeTextView.visible(account.bot)
|
||||
|
||||
Picasso.with(this)
|
||||
Glide.with(this)
|
||||
.load(account.avatar)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(accountAvatarImageView)
|
||||
Picasso.with(this)
|
||||
Glide.with(this)
|
||||
.load(account.header)
|
||||
.fit() // prevents crash with large header images
|
||||
.centerCrop()
|
||||
.into(accountHeaderImageView)
|
||||
|
||||
|
@ -357,7 +356,7 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
|||
accountMovedDisplayName.text = movedAccount.name
|
||||
accountMovedUsername.text = getString(R.string.status_username_format, movedAccount.username)
|
||||
|
||||
Picasso.with(this)
|
||||
Glide.with(this)
|
||||
.load(movedAccount.avatar)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(accountMovedAvatar)
|
||||
|
|
|
@ -27,6 +27,8 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
import com.keylesspalace.tusky.entity.Account
|
||||
|
@ -35,7 +37,6 @@ import com.keylesspalace.tusky.util.hide
|
|||
import com.keylesspalace.tusky.util.show
|
||||
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
||||
import com.keylesspalace.tusky.viewmodel.State
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
|
||||
import com.uber.autodispose.autoDisposable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
|
@ -208,9 +209,8 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
|||
fun bind(account: Account) {
|
||||
usernameTextView.text = account.username
|
||||
displayNameTextView.text = account.displayName
|
||||
Picasso.with(avatar.context)
|
||||
Glide.with(this@AccountsInListFragment)
|
||||
.load(account.avatar)
|
||||
.fit()
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar)
|
||||
}
|
||||
|
@ -255,9 +255,8 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
|||
fun bind(account: Account, inAList: Boolean) {
|
||||
usernameTextView.text = account.username
|
||||
displayNameTextView.text = account.displayName
|
||||
Picasso.with(avatar.context)
|
||||
Glide.with(this@AccountsInListFragment)
|
||||
.load(account.avatar)
|
||||
.fit()
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar)
|
||||
rejectButton.apply {
|
||||
|
|
|
@ -62,6 +62,7 @@ import android.widget.PopupMenu;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.gson.Gson;
|
||||
|
@ -97,7 +98,6 @@ import com.keylesspalace.tusky.view.ProgressImageView;
|
|||
import com.keylesspalace.tusky.view.TootButton;
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
||||
import com.mikepenz.iconics.IconicsDrawable;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
@ -286,7 +286,7 @@ public final class ComposeActivity
|
|||
if (TextUtils.isEmpty(activeAccount.getProfilePictureUrl())) {
|
||||
composeAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Picasso.with(this).load(activeAccount.getProfilePictureUrl())
|
||||
Glide.with(this).load(activeAccount.getProfilePictureUrl())
|
||||
.error(R.drawable.avatar_default)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(composeAvatar);
|
||||
|
|
|
@ -34,6 +34,7 @@ import android.view.Menu
|
|||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.adapter.AccountFieldEditAdapter
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||
|
@ -42,7 +43,6 @@ import com.keylesspalace.tusky.util.*
|
|||
import com.keylesspalace.tusky.viewmodel.EditProfileViewModel
|
||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.theartofdev.edmodo.cropper.CropImage
|
||||
import kotlinx.android.synthetic.main.activity_edit_profile.*
|
||||
import kotlinx.android.synthetic.main.toolbar_basic.*
|
||||
|
@ -133,14 +133,14 @@ class EditProfileActivity : BaseActivity(), Injectable {
|
|||
addFieldButton.isEnabled = me.source?.fields?.size ?: 0 < MAX_ACCOUNT_FIELDS
|
||||
|
||||
if(viewModel.avatarData.value == null) {
|
||||
Picasso.with(this)
|
||||
Glide.with(this)
|
||||
.load(me.avatar)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatarPreview)
|
||||
}
|
||||
|
||||
if(viewModel.headerData.value == null) {
|
||||
Picasso.with(this)
|
||||
Glide.with(this)
|
||||
.load(me.header)
|
||||
.into(headerPreview)
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import android.os.Bundle;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
|
@ -68,7 +69,6 @@ import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem;
|
|||
import com.mikepenz.materialdrawer.model.interfaces.IProfile;
|
||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
|
||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -334,12 +334,12 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
DrawerImageLoader.init(new AbstractDrawerImageLoader() {
|
||||
@Override
|
||||
public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) {
|
||||
Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView);
|
||||
Glide.with(MainActivity.this).load(uri).placeholder(placeholder).into(imageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(ImageView imageView) {
|
||||
Picasso.with(imageView.getContext()).cancelRequest(imageView);
|
||||
Glide.with(MainActivity.this).clear(imageView);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -541,7 +541,7 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
|||
|
||||
ImageView background = headerResult.getHeaderBackgroundView();
|
||||
|
||||
Picasso.with(MainActivity.this)
|
||||
Glide.with(MainActivity.this)
|
||||
.load(me.getHeader())
|
||||
.into(background);
|
||||
|
||||
|
|
|
@ -26,14 +26,12 @@ import android.preference.PreferenceManager;
|
|||
import androidx.emoji.text.EmojiCompat;
|
||||
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.jakewharton.picasso.OkHttp3Downloader;
|
||||
import com.keylesspalace.tusky.db.AccountManager;
|
||||
import com.keylesspalace.tusky.db.AppDatabase;
|
||||
import com.keylesspalace.tusky.di.AppInjector;
|
||||
import com.keylesspalace.tusky.util.EmojiCompatFont;
|
||||
import com.keylesspalace.tusky.util.LocaleManager;
|
||||
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
|
||||
|
@ -98,7 +96,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
};
|
||||
|
||||
initAppInjector();
|
||||
initPicasso();
|
||||
initEmojiCompat();
|
||||
|
||||
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
||||
|
@ -142,17 +139,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
|||
AppInjector.INSTANCE.init(this);
|
||||
}
|
||||
|
||||
protected void initPicasso() {
|
||||
// Initialize Picasso configuration
|
||||
Picasso.Builder builder = new Picasso.Builder(this);
|
||||
builder.downloader(new OkHttp3Downloader(okHttpClient));
|
||||
if (BuildConfig.DEBUG) {
|
||||
builder.listener((picasso, uri, exception) -> exception.printStackTrace());
|
||||
}
|
||||
|
||||
Picasso.setSingletonInstance(builder.build());
|
||||
}
|
||||
|
||||
public ServiceLocator getServiceLocator() {
|
||||
return serviceLocator;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.content.Intent
|
|||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
|
@ -39,6 +38,9 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.webkit.MimeTypeMap
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.FutureTarget
|
||||
import com.keylesspalace.tusky.BuildConfig.APPLICATION_ID
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
import com.keylesspalace.tusky.fragment.ViewImageFragment
|
||||
|
@ -48,8 +50,11 @@ import com.keylesspalace.tusky.pager.ImagePagerAdapter
|
|||
import com.keylesspalace.tusky.util.CollectionUtil.map
|
||||
import com.keylesspalace.tusky.util.getTemporaryMediaFilename
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.squareup.picasso.Target
|
||||
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
|
||||
import com.uber.autodispose.autoDisposable
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
||||
import kotlinx.android.synthetic.main.activity_view_media.*
|
||||
|
||||
|
@ -110,20 +115,21 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
attachments = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENTS)
|
||||
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
|
||||
|
||||
val adapter = if(attachments != null) {
|
||||
val adapter = if (attachments != null) {
|
||||
val realAttachs = map(attachments, AttachmentViewData::attachment)
|
||||
// Setup the view pager.
|
||||
ImagePagerAdapter(supportFragmentManager, realAttachs, initialPosition)
|
||||
|
||||
} else {
|
||||
val avatarUrl = intent.getStringExtra(EXTRA_AVATAR_URL) ?: throw IllegalArgumentException("attachment list or avatar url has to be set")
|
||||
val avatarUrl = intent.getStringExtra(EXTRA_AVATAR_URL)
|
||||
?: throw IllegalArgumentException("attachment list or avatar url has to be set")
|
||||
|
||||
AvatarImagePagerAdapter(supportFragmentManager, avatarUrl)
|
||||
}
|
||||
|
||||
viewPager.adapter = adapter
|
||||
viewPager.currentItem = initialPosition
|
||||
viewPager.addOnPageChangeListener(object: ViewPager.SimpleOnPageChangeListener() {
|
||||
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||
override fun onPageSelected(position: Int) {
|
||||
toolbar.title = adapter.getPageTitle(position)
|
||||
}
|
||||
|
@ -153,13 +159,18 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
if(attachments != null) {
|
||||
if (attachments != null) {
|
||||
menuInflater.inflate(R.menu.view_media_toolbar, menu)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||
menu?.findItem(R.id.action_share_media)?.isEnabled = !isCreating
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onBringUp() {
|
||||
supportStartPostponedEnterTransition()
|
||||
}
|
||||
|
@ -173,11 +184,19 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
for (listener in toolbarVisibilityListeners) {
|
||||
listener.onToolbarVisiblityChanged(toolbarVisible)
|
||||
}
|
||||
val visibility = if(toolbarVisible){ View.VISIBLE } else { View.INVISIBLE }
|
||||
val alpha = if(toolbarVisible){ 1.0f } else { 0.0f }
|
||||
val visibility = if (toolbarVisible) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.INVISIBLE
|
||||
}
|
||||
val alpha = if (toolbarVisible) {
|
||||
1.0f
|
||||
} else {
|
||||
0.0f
|
||||
}
|
||||
|
||||
toolbar.animate().alpha(alpha)
|
||||
.setListener(object: AnimatorListenerAdapter() {
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
toolbar.visibility = visibility
|
||||
animation.removeListener(this)
|
||||
|
@ -226,7 +245,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
}
|
||||
|
||||
val attachment = attachments!![viewPager.currentItem].attachment
|
||||
when(attachment.type) {
|
||||
when (attachment.type) {
|
||||
Attachment.Type.IMAGE -> shareImage(directory, attachment.url)
|
||||
Attachment.Type.VIDEO,
|
||||
Attachment.Type.GIFV -> shareVideo(directory, attachment.url)
|
||||
|
@ -243,30 +262,54 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
|||
}
|
||||
|
||||
|
||||
private var isCreating: Boolean = false
|
||||
|
||||
private fun shareImage(directory: File, url: String) {
|
||||
isCreating = true
|
||||
progressBarShare.visibility = View.VISIBLE
|
||||
invalidateOptionsMenu()
|
||||
val file = File(directory, getTemporaryMediaFilename("png"))
|
||||
val futureTask: FutureTarget<Bitmap> =
|
||||
Glide.with(applicationContext).asBitmap().load(Uri.parse(url)).submit()
|
||||
Single.fromCallable {
|
||||
val bitmap = futureTask.get()
|
||||
try {
|
||||
val stream = FileOutputStream(file)
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
||||
stream.close()
|
||||
return@fromCallable true
|
||||
} catch (fnfe: FileNotFoundException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
} catch (ioe: IOException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
}
|
||||
return@fromCallable false
|
||||
|
||||
Picasso.with(applicationContext).load(Uri.parse(url)).into(object: Target {
|
||||
override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) {
|
||||
try {
|
||||
val stream = FileOutputStream(file)
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
||||
stream.close()
|
||||
} catch (fnfe: FileNotFoundException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
} catch (ioe: IOException) {
|
||||
Log.e(TAG, "Error writing temporary media.")
|
||||
}
|
||||
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnDispose {
|
||||
futureTask.cancel(true)
|
||||
}
|
||||
}
|
||||
.autoDisposable(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY))
|
||||
.subscribe(
|
||||
{ result ->
|
||||
Log.d(TAG, "Download image result: $result")
|
||||
isCreating = false
|
||||
invalidateOptionsMenu()
|
||||
progressBarShare.visibility = View.GONE
|
||||
if (result)
|
||||
shareFile(file, "image/png")
|
||||
},
|
||||
{ error ->
|
||||
isCreating = false
|
||||
invalidateOptionsMenu()
|
||||
progressBarShare.visibility = View.GONE
|
||||
Log.e(TAG, "Failed to download image", error)
|
||||
}
|
||||
)
|
||||
|
||||
override fun onBitmapFailed(errorDrawable: Drawable?) {
|
||||
Log.e(TAG, "Error loading temporary media.")
|
||||
}
|
||||
|
||||
override fun onPrepareLoad(placeHolderDrawable: Drawable?) { }
|
||||
})
|
||||
|
||||
shareFile(file, "image/png")
|
||||
}
|
||||
|
||||
private fun shareVideo(directory: File, url: String) {
|
||||
|
|
|
@ -21,10 +21,10 @@ import android.view.LayoutInflater
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.db.AccountEntity
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
||||
|
||||
|
@ -46,7 +46,7 @@ class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(con
|
|||
username.text = account.fullName
|
||||
displayName.text = CustomEmojiHelper.emojifyString(account.displayName, account.emojis, displayName)
|
||||
if (!TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||
Picasso.with(context)
|
||||
Glide.with(avatar)
|
||||
.load(account.profilePictureUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar)
|
||||
|
|
|
@ -8,12 +8,12 @@ import android.view.View;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.interfaces.LinkListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||
private TextView username;
|
||||
|
@ -39,8 +39,7 @@ class AccountViewHolder extends RecyclerView.ViewHolder {
|
|||
username.setText(formattedUsername);
|
||||
CharSequence emojifiedName = CustomEmojiHelper.emojifyString(account.getName(), account.getEmojis(), displayName);
|
||||
displayName.setText(emojifiedName);
|
||||
Context context = avatar.getContext();
|
||||
Picasso.with(context)
|
||||
Glide.with(avatar)
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
|
|
|
@ -24,11 +24,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
public class BlocksAdapter extends AccountAdapter {
|
||||
|
||||
|
@ -85,7 +85,7 @@ public class BlocksAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Picasso.with(avatar.getContext())
|
||||
Glide.with(avatar)
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
|
|
|
@ -25,11 +25,11 @@ import android.widget.Filterable;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -147,7 +147,7 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
|||
account.getEmojis(), accountViewHolder.displayName);
|
||||
accountViewHolder.displayName.setText(emojifiedName);
|
||||
if (!account.getAvatar().isEmpty()) {
|
||||
Picasso.with(context)
|
||||
Glide.with(accountViewHolder.avatar)
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(accountViewHolder.avatar);
|
||||
|
@ -188,7 +188,7 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
|||
emoji.getShortcode()
|
||||
);
|
||||
emojiViewHolder.shortcode.setText(formattedShortcode);
|
||||
Picasso.with(context)
|
||||
Glide.with(emojiViewHolder.preview)
|
||||
.load(emoji.getUrl())
|
||||
.into(emojiViewHolder.preview);
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.entity.Emoji
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener: OnEmojiSelectedListener) : RecyclerView.Adapter<EmojiAdapter.EmojiHolder>() {
|
||||
private val emojiList : List<Emoji>
|
||||
|
@ -42,7 +42,7 @@ class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener:
|
|||
override fun onBindViewHolder(viewHolder: EmojiAdapter.EmojiHolder, position: Int) {
|
||||
val emoji = emojiList[position]
|
||||
|
||||
Picasso.with(viewHolder.emojiImageView.context)
|
||||
Glide.with(viewHolder.emojiImageView)
|
||||
.load(emoji.url)
|
||||
.into(viewHolder.emojiImageView)
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
public class FollowRequestsAdapter extends AccountAdapter {
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class FollowRequestsAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Picasso.with(avatar.getContext())
|
||||
Glide.with(avatar)
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
|
|
|
@ -9,11 +9,11 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.interfaces.AccountActionListener;
|
||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
public class MutesAdapter extends AccountAdapter {
|
||||
|
||||
|
@ -71,7 +71,7 @@ public class MutesAdapter extends AccountAdapter {
|
|||
String format = username.getContext().getString(R.string.status_username_format);
|
||||
String formattedUsername = String.format(format, account.getUsername());
|
||||
username.setText(formattedUsername);
|
||||
Picasso.with(avatar.getContext())
|
||||
Glide.with(avatar)
|
||||
.load(account.getAvatar())
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
|
|
|
@ -33,6 +33,7 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Account;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
|
@ -46,7 +47,6 @@ import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
|||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.mikepenz.iconics.utils.Utils;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
@ -309,9 +309,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
if (TextUtils.isEmpty(account.getAvatar())) {
|
||||
avatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Picasso.with(context)
|
||||
Glide.with(avatar)
|
||||
.load(account.getAvatar())
|
||||
.fit()
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
}
|
||||
|
@ -487,12 +486,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
}
|
||||
|
||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||
Context context = statusAvatar.getContext();
|
||||
|
||||
if (TextUtils.isEmpty(statusAvatarUrl)) {
|
||||
statusAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Picasso.with(context)
|
||||
Glide.with(statusAvatar)
|
||||
.load(statusAvatarUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(statusAvatar);
|
||||
|
@ -501,7 +499,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
|||
if (TextUtils.isEmpty(notificationAvatarUrl)) {
|
||||
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Picasso.with(context)
|
||||
Glide.with(notificationAvatar)
|
||||
.load(notificationAvatarUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(notificationAvatar);
|
||||
|
|
|
@ -12,6 +12,7 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.entity.Attachment.Focus;
|
||||
|
@ -27,7 +28,6 @@ import com.keylesspalace.tusky.util.ThemeUtils;
|
|||
import com.keylesspalace.tusky.view.MediaPreviewImageView;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.mikepenz.iconics.utils.Utils;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
@ -182,7 +182,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (TextUtils.isEmpty(url)) {
|
||||
avatar.setImageResource(R.drawable.avatar_default);
|
||||
} else {
|
||||
Picasso.with(avatar.getContext())
|
||||
Glide.with(avatar)
|
||||
.load(url)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatar);
|
||||
|
@ -320,9 +320,6 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
final int n = Math.min(attachments.size(), Status.MAX_MEDIA_ATTACHMENTS);
|
||||
|
||||
final int maxW = context.getResources().getInteger(R.integer.media_max_width);
|
||||
final int maxH = context.getResources().getInteger(R.integer.media_max_height);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
String previewUrl = attachments.get(i).getPreviewUrl();
|
||||
String description = attachments.get(i).getDescription();
|
||||
|
@ -336,10 +333,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
mediaPreviews[i].setVisibility(View.VISIBLE);
|
||||
|
||||
if (TextUtils.isEmpty(previewUrl)) {
|
||||
Picasso.with(context)
|
||||
Glide.with(mediaPreviews[i])
|
||||
.load(mediaPreviewUnloadedId)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
.into(mediaPreviews[i]);
|
||||
} else {
|
||||
|
@ -349,23 +344,18 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
if (focus != null) { // If there is a focal point for this attachment:
|
||||
mediaPreviews[i].setFocalPoint(focus);
|
||||
|
||||
Picasso.with(context)
|
||||
Glide.with(mediaPreviews[i])
|
||||
.load(previewUrl)
|
||||
.placeholder(mediaPreviewUnloadedId)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
// Also pass the mediaPreview as a callback to ensure it is called
|
||||
// initially when the image gets loaded:
|
||||
.into(mediaPreviews[i], mediaPreviews[i]);
|
||||
.addListener(mediaPreviews[i])
|
||||
.into(mediaPreviews[i]);
|
||||
} else {
|
||||
mediaPreviews[i].removeFocalPoint();
|
||||
|
||||
Picasso.with(context)
|
||||
Glide.with(mediaPreviews[i])
|
||||
.load(previewUrl)
|
||||
.placeholder(mediaPreviewUnloadedId)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
.into(mediaPreviews[i]);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.widget.LinearLayout;
|
|||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.entity.Card;
|
||||
import com.keylesspalace.tusky.entity.Status;
|
||||
|
@ -23,7 +24,6 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
|||
import com.keylesspalace.tusky.util.CustomURLSpan;
|
||||
import com.keylesspalace.tusky.util.LinkHelper;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
@ -176,9 +176,8 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
|||
|
||||
cardView.setClipToOutline(true);
|
||||
|
||||
Picasso.with(cardImage.getContext())
|
||||
Glide.with(cardImage)
|
||||
.load(card.getImage())
|
||||
.fit()
|
||||
.centerCrop()
|
||||
.into(cardImage);
|
||||
|
||||
|
|
|
@ -19,15 +19,14 @@ import android.content.Context;
|
|||
import android.text.InputFilter;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -55,7 +54,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
|||
int padding = Utils.dpToPx(context, 12);
|
||||
avatar.setPaddingRelative(0, 0, padding, padding);
|
||||
avatarInset.setVisibility(View.VISIBLE);
|
||||
Picasso.with(context)
|
||||
Glide.with(context)
|
||||
.load(rebloggedUrl)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.into(avatarInset);
|
||||
|
|
|
@ -23,12 +23,12 @@ import android.widget.ImageView;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.keylesspalace.tusky.R;
|
||||
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder;
|
||||
import com.keylesspalace.tusky.entity.Attachment;
|
||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -122,7 +122,7 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
|
|||
for(int i=0; i < avatars.length; i++) {
|
||||
ImageView avatarView = avatars[i];
|
||||
if(i < accounts.size()) {
|
||||
Picasso.with(avatarView.getContext())
|
||||
Glide.with(avatarView)
|
||||
.load(accounts.get(i).getAvatar())
|
||||
.into(avatarView);
|
||||
avatarView.setVisibility(View.VISIBLE);
|
||||
|
|
|
@ -27,6 +27,8 @@ import androidx.core.content.ContextCompat
|
|||
import androidx.core.view.ViewCompat
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.ViewMediaActivity
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
|
@ -38,7 +40,6 @@ import com.keylesspalace.tusky.util.hide
|
|||
import com.keylesspalace.tusky.util.show
|
||||
import com.keylesspalace.tusky.view.SquareImageView
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.android.synthetic.main.fragment_timeline.*
|
||||
import retrofit2.Call
|
||||
import retrofit2.Callback
|
||||
|
@ -82,7 +83,7 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
|||
override fun onFailure(call: Call<List<Status>>?, t: Throwable?) {
|
||||
fetchingStatus = FetchingStatus.NOT_FETCHING
|
||||
|
||||
if(isAdded) {
|
||||
if (isAdded) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
progressBar.visibility = View.GONE
|
||||
statusView.show()
|
||||
|
@ -102,7 +103,7 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
|||
|
||||
override fun onResponse(call: Call<List<Status>>, response: Response<List<Status>>) {
|
||||
fetchingStatus = FetchingStatus.NOT_FETCHING
|
||||
if(isAdded) {
|
||||
if (isAdded) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
progressBar.visibility = View.GONE
|
||||
|
||||
|
@ -302,13 +303,8 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
|||
holder.imageView.setBackgroundColor(Color.HSVToColor(itemBgBaseHSV))
|
||||
val item = items[position]
|
||||
|
||||
val maxW = holder.imageView.context.resources.getInteger(R.integer.media_max_width)
|
||||
val maxH = holder.imageView.context.resources.getInteger(R.integer.media_max_height)
|
||||
|
||||
Picasso.with(holder.imageView.context)
|
||||
Glide.with(holder.imageView)
|
||||
.load(item.attachment.previewUrl)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
.into(holder.imageView)
|
||||
}
|
||||
|
|
|
@ -18,21 +18,24 @@ package com.keylesspalace.tusky.fragment
|
|||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.engine.GlideException
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.target.Target
|
||||
|
||||
import com.github.chrisbanes.photoview.PhotoViewAttacher
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
import com.keylesspalace.tusky.util.hide
|
||||
import com.keylesspalace.tusky.util.visible
|
||||
import com.squareup.picasso.Callback
|
||||
import com.squareup.picasso.NetworkPolicy
|
||||
import com.squareup.picasso.Picasso
|
||||
import kotlinx.android.synthetic.main.activity_view_media.*
|
||||
import kotlinx.android.synthetic.main.fragment_view_image.*
|
||||
|
||||
|
@ -46,7 +49,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
|||
private lateinit var attacher: PhotoViewAttacher
|
||||
private lateinit var photoActionsListener: PhotoActionsListener
|
||||
private lateinit var toolbar: View
|
||||
override lateinit var descriptionView : TextView
|
||||
override lateinit var descriptionView: TextView
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
|
@ -74,53 +77,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
|||
result
|
||||
}
|
||||
|
||||
val maxW = photoView.context.resources.getInteger(R.integer.media_max_width)
|
||||
val maxH = photoView.context.resources.getInteger(R.integer.media_max_height)
|
||||
|
||||
// If we are the view to be shown initially...
|
||||
if (arguments!!.getBoolean(ViewMediaFragment.ARG_START_POSTPONED_TRANSITION)) {
|
||||
// Try to load image from disk.
|
||||
Picasso.with(context)
|
||||
.load(url)
|
||||
.noFade()
|
||||
.networkPolicy(NetworkPolicy.OFFLINE)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
.into(photoView, object : Callback {
|
||||
override fun onSuccess() {
|
||||
// if we loaded image from disk, we should check that view is attached.
|
||||
if (photoView?.isAttachedToWindow == true) {
|
||||
finishLoadingSuccessfully()
|
||||
} else {
|
||||
// if view is not attached yet, wait for an attachment and
|
||||
// start transition when it's finally ready.
|
||||
photoView?.addOnAttachStateChangeListener(
|
||||
object : View.OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View?) {
|
||||
finishLoadingSuccessfully()
|
||||
photoView.removeOnAttachStateChangeListener(this)
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View?) {}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
// if there's no image in cache, load from network and start transition
|
||||
// immediately.
|
||||
if (isAdded) {
|
||||
photoActionsListener.onBringUp()
|
||||
loadImageFromNetwork(url, photoView)
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// if we're not initial page, don't bother.
|
||||
loadImageFromNetwork(url, photoView)
|
||||
}
|
||||
|
||||
loadImageFromNetwork(url, photoView)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
|
@ -134,7 +91,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
|||
val arguments = this.arguments!!
|
||||
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
||||
val url: String?
|
||||
var description : String? = null
|
||||
var description: String? = null
|
||||
|
||||
if (attachment != null) {
|
||||
url = attachment.url
|
||||
|
@ -169,35 +126,53 @@ class ViewImageFragment : ViewMediaFragment() {
|
|||
.start()
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
Picasso.with(context).cancelRequest(photoView)
|
||||
override fun onDestroyView() {
|
||||
Glide.with(this).clear(photoView)
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
private fun loadImageFromNetwork(url: String, photoView: ImageView) {
|
||||
val maxW = photoView.context.resources.getInteger(R.integer.media_max_width)
|
||||
val maxH = photoView.context.resources.getInteger(R.integer.media_max_height)
|
||||
private fun loadImageFromNetwork(url: String, photoView: ImageView) =
|
||||
//Request image from the any cache
|
||||
Glide.with(this)
|
||||
.load(url)
|
||||
.dontAnimate()
|
||||
.onlyRetrieveFromCache(true)
|
||||
.error(
|
||||
//Request image from the network on fail load image from cache
|
||||
Glide.with(this)
|
||||
.load(url)
|
||||
.centerInside()
|
||||
.addListener(ImageRequestListener(false))
|
||||
)
|
||||
.centerInside()
|
||||
.addListener(ImageRequestListener(true))
|
||||
.into(photoView)
|
||||
|
||||
Picasso.with(context)
|
||||
.load(url)
|
||||
.noPlaceholder()
|
||||
.networkPolicy(NetworkPolicy.NO_STORE)
|
||||
.resize(maxW, maxH)
|
||||
.onlyScaleDown()
|
||||
.centerInside()
|
||||
.into(photoView, object : Callback {
|
||||
override fun onSuccess() {
|
||||
finishLoadingSuccessfully()
|
||||
}
|
||||
|
||||
override fun onError() {
|
||||
progressBar?.hide()
|
||||
}
|
||||
})
|
||||
/**
|
||||
* @param isCacheRequest - is this listener for request image from cache or from the network
|
||||
*/
|
||||
private inner class ImageRequestListener(private val isCacheRequest: Boolean) : RequestListener<Drawable> {
|
||||
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
|
||||
if (isCacheRequest) //Complete the transition on failed image from cache
|
||||
completeTransition()
|
||||
else
|
||||
progressBar?.hide() //Hide progress bar only on fail request from internet
|
||||
return false
|
||||
}
|
||||
|
||||
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
|
||||
progressBar?.hide() //Always hide the progress bar on success
|
||||
resource?.let {
|
||||
target?.onResourceReady(resource, null)
|
||||
if (isCacheRequest) completeTransition() //Complete transition on cache request only, because transition already completed on Network request
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
private fun finishLoadingSuccessfully() {
|
||||
progressBar?.hide()
|
||||
private fun completeTransition() {
|
||||
attacher.update()
|
||||
photoActionsListener.onBringUp()
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ import android.os.Bundle
|
|||
import android.service.chooser.ChooserTarget
|
||||
import android.service.chooser.ChooserTargetService
|
||||
import android.text.TextUtils
|
||||
import com.bumptech.glide.Glide
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.TuskyApplication
|
||||
import com.keylesspalace.tusky.db.AccountManager
|
||||
import com.keylesspalace.tusky.di.Injectable
|
||||
import com.keylesspalace.tusky.util.NotificationHelper
|
||||
import com.squareup.picasso.Picasso
|
||||
|
||||
|
||||
@TargetApi(23)
|
||||
|
@ -48,10 +48,13 @@ class AccountChooserService : ChooserTargetService(), Injectable {
|
|||
val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||
Icon.createWithResource(applicationContext, R.drawable.avatar_default)
|
||||
} else {
|
||||
Icon.createWithBitmap(Picasso.with(this).load(account.profilePictureUrl)
|
||||
val bmp = Glide.with(this)
|
||||
.asBitmap()
|
||||
.load(account.profilePictureUrl)
|
||||
.error(R.drawable.avatar_default)
|
||||
.placeholder(R.drawable.avatar_default)
|
||||
.get())
|
||||
.submit()
|
||||
Icon.createWithBitmap(bmp.get())
|
||||
}
|
||||
val bundle = Bundle()
|
||||
bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id)
|
||||
|
|
|
@ -20,23 +20,26 @@ import android.graphics.Canvas;
|
|||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.Spanned;
|
||||
import android.text.SpannedString;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.view.View;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.request.target.CustomTarget;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
import com.bumptech.glide.request.transition.Transition;
|
||||
import com.keylesspalace.tusky.entity.Emoji;
|
||||
import com.squareup.picasso.Picasso;
|
||||
import com.squareup.picasso.Target;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class CustomEmojiHelper {
|
||||
|
||||
/**
|
||||
|
@ -55,13 +58,13 @@ public class CustomEmojiHelper {
|
|||
CharSequence pattern = new StringBuilder(":").append(emoji.getShortcode()).append(':');
|
||||
Matcher matcher = Pattern.compile(pattern.toString()).matcher(text);
|
||||
while (matcher.find()) {
|
||||
// We keep a span as a Picasso target, because Picasso keeps weak reference to
|
||||
// the target so an anonymous class would likely be garbage collected.
|
||||
EmojiSpan span = new EmojiSpan(view);
|
||||
builder.setSpan(span, matcher.start(), matcher.end(), 0);
|
||||
Picasso.with(view.getContext())
|
||||
Glide.with(view)
|
||||
.asBitmap()
|
||||
.load(emoji.getUrl())
|
||||
.into(span);
|
||||
.into(span.getTarget());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +79,7 @@ public class CustomEmojiHelper {
|
|||
}
|
||||
|
||||
|
||||
public static class EmojiSpan extends ReplacementSpan implements Target {
|
||||
public static class EmojiSpan extends ReplacementSpan {
|
||||
|
||||
private @Nullable Drawable imageDrawable;
|
||||
private WeakReference<View> viewWeakReference;
|
||||
|
@ -118,20 +121,23 @@ public class CustomEmojiHelper {
|
|||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
||||
View view = viewWeakReference.get();
|
||||
if(view != null) {
|
||||
imageDrawable = new BitmapDrawable(view.getContext().getResources(), bitmap);
|
||||
view.invalidate();
|
||||
}
|
||||
Target<Bitmap> getTarget(){
|
||||
return new CustomTarget<Bitmap>() {
|
||||
@Override
|
||||
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
|
||||
View view = viewWeakReference.get();
|
||||
if (view != null) {
|
||||
imageDrawable = new BitmapDrawable(view.getContext().getResources(), resource);
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadCleared(@Nullable Drawable placeholder) {
|
||||
//Do nothing on load cleared
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBitmapFailed(Drawable errorDrawable) {}
|
||||
|
||||
@Override
|
||||
public void onPrepareLoad(Drawable placeHolderDrawable) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,10 +16,8 @@
|
|||
package com.keylesspalace.tusky.util
|
||||
|
||||
import android.graphics.Matrix
|
||||
import android.widget.ImageView
|
||||
|
||||
import com.keylesspalace.tusky.entity.Attachment.Focus
|
||||
import com.squareup.picasso.Callback
|
||||
|
||||
/**
|
||||
* Calculates the image matrix needed to maintain the correct cropping for image views based on
|
||||
|
@ -88,10 +86,10 @@ object FocalPointUtil {
|
|||
*/
|
||||
fun calculateScaling(viewWidth: Float, viewHeight: Float,
|
||||
imageWidth: Float, imageHeight: Float): Float {
|
||||
if (isVerticalCrop(viewWidth, viewHeight, imageWidth, imageHeight)) {
|
||||
return viewWidth / imageWidth
|
||||
return if (isVerticalCrop(viewWidth, viewHeight, imageWidth, imageHeight)) {
|
||||
viewWidth / imageWidth
|
||||
} else { // horizontal crop:
|
||||
return viewHeight / imageHeight
|
||||
viewHeight / imageHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ import androidx.core.content.ContextCompat;
|
|||
import androidx.core.text.BidiFormatter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
|
||||
import com.bumptech.glide.request.FutureTarget;
|
||||
import com.evernote.android.job.JobManager;
|
||||
import com.evernote.android.job.JobRequest;
|
||||
import com.keylesspalace.tusky.BuildConfig;
|
||||
|
@ -48,17 +51,15 @@ import com.keylesspalace.tusky.entity.Notification;
|
|||
import com.keylesspalace.tusky.entity.Status;
|
||||
import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver;
|
||||
import com.keylesspalace.tusky.receiver.SendStatusBroadcastReceiver;
|
||||
import com.keylesspalace.tusky.view.RoundedTransformation;
|
||||
import com.squareup.picasso.Picasso;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public class NotificationHelper {
|
||||
|
||||
|
@ -169,11 +170,14 @@ public class NotificationHelper {
|
|||
//load the avatar synchronously
|
||||
Bitmap accountAvatar;
|
||||
try {
|
||||
accountAvatar = Picasso.with(context)
|
||||
FutureTarget<Bitmap> target = Glide.with(context)
|
||||
.asBitmap()
|
||||
.load(body.getAccount().getAvatar())
|
||||
.transform(new RoundedTransformation(20))
|
||||
.get();
|
||||
} catch (IOException e) {
|
||||
.transform(new RoundedCorners(20))
|
||||
.submit();
|
||||
|
||||
accountAvatar = target.get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Log.d(TAG, "error loading account avatar", e);
|
||||
accountAvatar = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar_default);
|
||||
}
|
||||
|
|
|
@ -16,12 +16,16 @@ package com.keylesspalace.tusky.view
|
|||
|
||||
import android.content.Context
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.engine.GlideException
|
||||
import com.bumptech.glide.request.RequestListener
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.keylesspalace.tusky.entity.Attachment
|
||||
|
||||
import com.keylesspalace.tusky.util.FocalPointUtil
|
||||
import com.squareup.picasso.Callback
|
||||
|
||||
/**
|
||||
* This is an extension of the standard android ImageView, which makes sure to update the custom
|
||||
|
@ -39,7 +43,7 @@ class MediaPreviewImageView
|
|||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = 0
|
||||
) : AppCompatImageView(context, attrs, defStyleAttr), Callback {
|
||||
) : AppCompatImageView(context, attrs, defStyleAttr),RequestListener<Drawable> {
|
||||
private var focus: Attachment.Focus? = null
|
||||
private var focalMatrix: Matrix? = null
|
||||
|
||||
|
@ -94,18 +98,16 @@ defStyleAttr: Int = 0
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the image is first succesfully loaded by Picasso, this function makes sure
|
||||
* that the custom matrix of this image is initialized if a focus point is set.
|
||||
*/
|
||||
override fun onSuccess() {
|
||||
onSizeChanged(width, height, width, height)
|
||||
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
|
||||
return false
|
||||
}
|
||||
|
||||
// We do not handle the error here, instead it will be handled higher up the call chain.
|
||||
override fun onError() {
|
||||
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
|
||||
onSizeChanged(width, height, width, height)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when the size of the view changes, it calls the FocalPointUtil to update the
|
||||
* matrix if we have a set focal point. It then reassigns the matrix to this imageView.
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/* Copyright 2017 Andrew Dawson
|
||||
*
|
||||
* This file is a part of Tusky.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
|
||||
* Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with Tusky; if not,
|
||||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
package com.keylesspalace.tusky.view;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
|
||||
import com.squareup.picasso.Transformation;
|
||||
|
||||
public class RoundedTransformation implements Transformation {
|
||||
|
||||
private final float percent;
|
||||
|
||||
/** 100% would mean a perfectly round image **/
|
||||
public RoundedTransformation(final float percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bitmap transform(Bitmap source) {
|
||||
|
||||
final int width = source.getWidth();
|
||||
final int height = source.getHeight();
|
||||
final int shorterSide;
|
||||
if (width > height) {
|
||||
shorterSide = height;
|
||||
} else {
|
||||
shorterSide = width;
|
||||
}
|
||||
|
||||
final float radius = shorterSide / 2 * percent / 100;
|
||||
|
||||
final Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setShader(new BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
|
||||
|
||||
Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(output);
|
||||
|
||||
canvas.drawRoundRect(new RectF(0, 0, width, height), radius, radius, paint);
|
||||
|
||||
if (source != output) {
|
||||
source.recycle();
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String key() {
|
||||
return "rounded "+percent+"%";
|
||||
}
|
||||
}
|
|
@ -89,8 +89,8 @@
|
|||
android:layout_marginStart="12dp"
|
||||
android:layout_marginTop="12dp"
|
||||
license:license="@string/license_apache_2"
|
||||
license:link="https://square.github.io/picasso/"
|
||||
license:name="Picasso" />
|
||||
license:link="https://bumptech.github.io/glide/"
|
||||
license:name="Glide" />
|
||||
|
||||
<com.keylesspalace.tusky.view.LicenseCard
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -17,4 +17,12 @@
|
|||
android:background="@color/toolbar_view_media"
|
||||
android:theme="@style/AppTheme.Account.AppBarLayout"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBarShare"
|
||||
style="?android:attr/progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -16,10 +16,6 @@ class FakeTuskyApplication : TuskyApplication() {
|
|||
// No-op
|
||||
}
|
||||
|
||||
override fun initPicasso() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
override fun getServiceLocator(): ServiceLocator {
|
||||
return locator
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue