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
db51c23717
commit
76ce28980c
32 changed files with 260 additions and 322 deletions
|
@ -99,11 +99,9 @@ dependencies {
|
||||||
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2: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:okhttp:3.14.0'
|
||||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.0'
|
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.0'
|
||||||
implementation 'org.conscrypt:conscrypt-android:2.1.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.connyduck:sparkbutton:2.0.0'
|
||||||
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
implementation 'com.github.chrisbanes:PhotoView:2.3.0'
|
||||||
implementation 'com.mikepenz:google-material-typeface:3.0.1.3.original@aar'
|
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-android-archcomponents:1.2.0'
|
||||||
implementation 'com.uber.autodispose:autodispose-ktx:1.2.0'
|
implementation 'com.uber.autodispose:autodispose-ktx:1.2.0'
|
||||||
implementation 'androidx.paging:paging-runtime-ktx:2.1.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'
|
||||||
}
|
}
|
||||||
|
|
11
app/proguard-rules.pro
vendored
11
app/proguard-rules.pro
vendored
|
@ -49,9 +49,6 @@
|
||||||
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
-dontwarn org.codehaus.mojo.animal_sniffer.*
|
||||||
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
-dontwarn okhttp3.internal.platform.ConscryptPlatform
|
||||||
|
|
||||||
## for picasso
|
|
||||||
-dontwarn com.squareup.okhttp.**
|
|
||||||
|
|
||||||
##for keep
|
##for keep
|
||||||
-dontwarn android.arch.util.paging.CountedDataSource
|
-dontwarn android.arch.util.paging.CountedDataSource
|
||||||
-dontwarn android.arch.persistence.room.paging.LimitOffsetDataSource
|
-dontwarn android.arch.persistence.room.paging.LimitOffsetDataSource
|
||||||
|
@ -100,3 +97,11 @@
|
||||||
# work around a bug in proguard
|
# work around a bug in proguard
|
||||||
# see https://sourceforge.net/p/proguard/bugs/729/
|
# see https://sourceforge.net/p/proguard/bugs/729/
|
||||||
-keepnames public interface com.uber.autodispose.lifecycle.CorrespondingEventsFunction { *; }
|
-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.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
import com.google.android.material.appbar.CollapsingToolbarLayout
|
import com.google.android.material.appbar.CollapsingToolbarLayout
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
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.pager.AccountPagerAdapter
|
||||||
import com.keylesspalace.tusky.util.*
|
import com.keylesspalace.tusky.util.*
|
||||||
import com.keylesspalace.tusky.viewmodel.AccountViewModel
|
import com.keylesspalace.tusky.viewmodel.AccountViewModel
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
import dagger.android.AndroidInjector
|
import dagger.android.AndroidInjector
|
||||||
import dagger.android.DispatchingAndroidInjector
|
import dagger.android.DispatchingAndroidInjector
|
||||||
import dagger.android.support.HasSupportFragmentInjector
|
import dagger.android.support.HasSupportFragmentInjector
|
||||||
|
@ -321,13 +321,12 @@ class AccountActivity : BottomSheetActivity(), ActionButtonActivity, HasSupportF
|
||||||
accountLockedImageView.visible(account.locked)
|
accountLockedImageView.visible(account.locked)
|
||||||
accountBadgeTextView.visible(account.bot)
|
accountBadgeTextView.visible(account.bot)
|
||||||
|
|
||||||
Picasso.with(this)
|
Glide.with(this)
|
||||||
.load(account.avatar)
|
.load(account.avatar)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(accountAvatarImageView)
|
.into(accountAvatarImageView)
|
||||||
Picasso.with(this)
|
Glide.with(this)
|
||||||
.load(account.header)
|
.load(account.header)
|
||||||
.fit() // prevents crash with large header images
|
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(accountHeaderImageView)
|
.into(accountHeaderImageView)
|
||||||
|
|
||||||
|
@ -357,7 +356,7 @@ 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)
|
||||||
|
|
||||||
Picasso.with(this)
|
Glide.with(this)
|
||||||
.load(movedAccount.avatar)
|
.load(movedAccount.avatar)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(accountMovedAvatar)
|
.into(accountMovedAvatar)
|
||||||
|
|
|
@ -27,6 +27,8 @@ import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.Injectable
|
||||||
import com.keylesspalace.tusky.di.ViewModelFactory
|
import com.keylesspalace.tusky.di.ViewModelFactory
|
||||||
import com.keylesspalace.tusky.entity.Account
|
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.util.show
|
||||||
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
import com.keylesspalace.tusky.viewmodel.AccountsInListViewModel
|
||||||
import com.keylesspalace.tusky.viewmodel.State
|
import com.keylesspalace.tusky.viewmodel.State
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
|
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider.from
|
||||||
import com.uber.autodispose.autoDisposable
|
import com.uber.autodispose.autoDisposable
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
@ -208,9 +209,8 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
||||||
fun bind(account: Account) {
|
fun bind(account: Account) {
|
||||||
usernameTextView.text = account.username
|
usernameTextView.text = account.username
|
||||||
displayNameTextView.text = account.displayName
|
displayNameTextView.text = account.displayName
|
||||||
Picasso.with(avatar.context)
|
Glide.with(this@AccountsInListFragment)
|
||||||
.load(account.avatar)
|
.load(account.avatar)
|
||||||
.fit()
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar)
|
.into(avatar)
|
||||||
}
|
}
|
||||||
|
@ -255,9 +255,8 @@ class AccountsInListFragment : DialogFragment(), Injectable {
|
||||||
fun bind(account: Account, inAList: Boolean) {
|
fun bind(account: Account, inAList: Boolean) {
|
||||||
usernameTextView.text = account.username
|
usernameTextView.text = account.username
|
||||||
displayNameTextView.text = account.displayName
|
displayNameTextView.text = account.displayName
|
||||||
Picasso.with(avatar.context)
|
Glide.with(this@AccountsInListFragment)
|
||||||
.load(account.avatar)
|
.load(account.avatar)
|
||||||
.fit()
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar)
|
.into(avatar)
|
||||||
rejectButton.apply {
|
rejectButton.apply {
|
||||||
|
|
|
@ -62,6 +62,7 @@ import android.widget.PopupMenu;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
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;
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
@ -97,7 +98,6 @@ import com.keylesspalace.tusky.view.ProgressImageView;
|
||||||
import com.keylesspalace.tusky.view.TootButton;
|
import com.keylesspalace.tusky.view.TootButton;
|
||||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
|
||||||
import com.mikepenz.iconics.IconicsDrawable;
|
import com.mikepenz.iconics.IconicsDrawable;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ public final class ComposeActivity
|
||||||
if (TextUtils.isEmpty(activeAccount.getProfilePictureUrl())) {
|
if (TextUtils.isEmpty(activeAccount.getProfilePictureUrl())) {
|
||||||
composeAvatar.setImageResource(R.drawable.avatar_default);
|
composeAvatar.setImageResource(R.drawable.avatar_default);
|
||||||
} else {
|
} else {
|
||||||
Picasso.with(this).load(activeAccount.getProfilePictureUrl())
|
Glide.with(this).load(activeAccount.getProfilePictureUrl())
|
||||||
.error(R.drawable.avatar_default)
|
.error(R.drawable.avatar_default)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(composeAvatar);
|
.into(composeAvatar);
|
||||||
|
|
|
@ -34,6 +34,7 @@ import android.view.Menu
|
||||||
import android.view.MenuItem
|
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.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
|
||||||
|
@ -42,7 +43,6 @@ import com.keylesspalace.tusky.util.*
|
||||||
import com.keylesspalace.tusky.viewmodel.EditProfileViewModel
|
import com.keylesspalace.tusky.viewmodel.EditProfileViewModel
|
||||||
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
import com.mikepenz.google_material_typeface_library.GoogleMaterial
|
||||||
import com.mikepenz.iconics.IconicsDrawable
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
import com.theartofdev.edmodo.cropper.CropImage
|
import com.theartofdev.edmodo.cropper.CropImage
|
||||||
import kotlinx.android.synthetic.main.activity_edit_profile.*
|
import kotlinx.android.synthetic.main.activity_edit_profile.*
|
||||||
import kotlinx.android.synthetic.main.toolbar_basic.*
|
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
|
addFieldButton.isEnabled = me.source?.fields?.size ?: 0 < MAX_ACCOUNT_FIELDS
|
||||||
|
|
||||||
if(viewModel.avatarData.value == null) {
|
if(viewModel.avatarData.value == null) {
|
||||||
Picasso.with(this)
|
Glide.with(this)
|
||||||
.load(me.avatar)
|
.load(me.avatar)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatarPreview)
|
.into(avatarPreview)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(viewModel.headerData.value == null) {
|
if(viewModel.headerData.value == null) {
|
||||||
Picasso.with(this)
|
Glide.with(this)
|
||||||
.load(me.header)
|
.load(me.header)
|
||||||
.into(headerPreview)
|
.into(headerPreview)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import android.os.Bundle;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
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.model.interfaces.IProfile;
|
||||||
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
|
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
|
||||||
import com.mikepenz.materialdrawer.util.DrawerImageLoader;
|
import com.mikepenz.materialdrawer.util.DrawerImageLoader;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -334,12 +334,12 @@ public final class MainActivity extends BottomSheetActivity implements ActionBut
|
||||||
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) {
|
||||||
Picasso.with(imageView.getContext()).load(uri).placeholder(placeholder).into(imageView);
|
Glide.with(MainActivity.this).load(uri).placeholder(placeholder).into(imageView);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancel(ImageView imageView) {
|
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();
|
ImageView background = headerResult.getHeaderBackgroundView();
|
||||||
|
|
||||||
Picasso.with(MainActivity.this)
|
Glide.with(MainActivity.this)
|
||||||
.load(me.getHeader())
|
.load(me.getHeader())
|
||||||
.into(background);
|
.into(background);
|
||||||
|
|
||||||
|
|
|
@ -26,14 +26,12 @@ import android.preference.PreferenceManager;
|
||||||
import androidx.emoji.text.EmojiCompat;
|
import androidx.emoji.text.EmojiCompat;
|
||||||
|
|
||||||
import com.evernote.android.job.JobManager;
|
import com.evernote.android.job.JobManager;
|
||||||
import com.jakewharton.picasso.OkHttp3Downloader;
|
|
||||||
import com.keylesspalace.tusky.db.AccountManager;
|
import com.keylesspalace.tusky.db.AccountManager;
|
||||||
import com.keylesspalace.tusky.db.AppDatabase;
|
import com.keylesspalace.tusky.db.AppDatabase;
|
||||||
import com.keylesspalace.tusky.di.AppInjector;
|
import com.keylesspalace.tusky.di.AppInjector;
|
||||||
import com.keylesspalace.tusky.util.EmojiCompatFont;
|
import com.keylesspalace.tusky.util.EmojiCompatFont;
|
||||||
import com.keylesspalace.tusky.util.LocaleManager;
|
import com.keylesspalace.tusky.util.LocaleManager;
|
||||||
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
import com.keylesspalace.tusky.util.NotificationPullJobCreator;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import org.conscrypt.Conscrypt;
|
import org.conscrypt.Conscrypt;
|
||||||
|
|
||||||
|
@ -98,7 +96,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
};
|
};
|
||||||
|
|
||||||
initAppInjector();
|
initAppInjector();
|
||||||
initPicasso();
|
|
||||||
initEmojiCompat();
|
initEmojiCompat();
|
||||||
|
|
||||||
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
JobManager.create(this).addJobCreator(notificationPullJobCreator);
|
||||||
|
@ -142,17 +139,6 @@ public class TuskyApplication extends Application implements HasActivityInjector
|
||||||
AppInjector.INSTANCE.init(this);
|
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() {
|
public ServiceLocator getServiceLocator() {
|
||||||
return serviceLocator;
|
return serviceLocator;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
@ -39,6 +38,9 @@ import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import android.widget.Toast
|
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.BuildConfig.APPLICATION_ID
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.fragment.ViewImageFragment
|
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.CollectionUtil.map
|
||||||
import com.keylesspalace.tusky.util.getTemporaryMediaFilename
|
import com.keylesspalace.tusky.util.getTemporaryMediaFilename
|
||||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||||
import com.squareup.picasso.Picasso
|
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
|
||||||
import com.squareup.picasso.Target
|
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.*
|
import kotlinx.android.synthetic.main.activity_view_media.*
|
||||||
|
|
||||||
|
@ -110,20 +115,21 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
||||||
attachments = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENTS)
|
attachments = intent.getParcelableArrayListExtra(EXTRA_ATTACHMENTS)
|
||||||
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
|
val initialPosition = intent.getIntExtra(EXTRA_ATTACHMENT_INDEX, 0)
|
||||||
|
|
||||||
val adapter = if(attachments != null) {
|
val adapter = if (attachments != null) {
|
||||||
val realAttachs = map(attachments, AttachmentViewData::attachment)
|
val realAttachs = map(attachments, AttachmentViewData::attachment)
|
||||||
// Setup the view pager.
|
// Setup the view pager.
|
||||||
ImagePagerAdapter(supportFragmentManager, realAttachs, initialPosition)
|
ImagePagerAdapter(supportFragmentManager, realAttachs, initialPosition)
|
||||||
|
|
||||||
} else {
|
} 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)
|
AvatarImagePagerAdapter(supportFragmentManager, avatarUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewPager.adapter = adapter
|
viewPager.adapter = adapter
|
||||||
viewPager.currentItem = initialPosition
|
viewPager.currentItem = initialPosition
|
||||||
viewPager.addOnPageChangeListener(object: ViewPager.SimpleOnPageChangeListener() {
|
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
toolbar.title = adapter.getPageTitle(position)
|
toolbar.title = adapter.getPageTitle(position)
|
||||||
}
|
}
|
||||||
|
@ -153,13 +159,18 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
if(attachments != null) {
|
if (attachments != null) {
|
||||||
menuInflater.inflate(R.menu.view_media_toolbar, menu)
|
menuInflater.inflate(R.menu.view_media_toolbar, menu)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onPrepareOptionsMenu(menu: Menu?): Boolean {
|
||||||
|
menu?.findItem(R.id.action_share_media)?.isEnabled = !isCreating
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBringUp() {
|
override fun onBringUp() {
|
||||||
supportStartPostponedEnterTransition()
|
supportStartPostponedEnterTransition()
|
||||||
}
|
}
|
||||||
|
@ -173,11 +184,19 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
||||||
for (listener in toolbarVisibilityListeners) {
|
for (listener in toolbarVisibilityListeners) {
|
||||||
listener.onToolbarVisiblityChanged(toolbarVisible)
|
listener.onToolbarVisiblityChanged(toolbarVisible)
|
||||||
}
|
}
|
||||||
val visibility = if(toolbarVisible){ View.VISIBLE } else { View.INVISIBLE }
|
val visibility = if (toolbarVisible) {
|
||||||
val alpha = if(toolbarVisible){ 1.0f } else { 0.0f }
|
View.VISIBLE
|
||||||
|
} else {
|
||||||
|
View.INVISIBLE
|
||||||
|
}
|
||||||
|
val alpha = if (toolbarVisible) {
|
||||||
|
1.0f
|
||||||
|
} else {
|
||||||
|
0.0f
|
||||||
|
}
|
||||||
|
|
||||||
toolbar.animate().alpha(alpha)
|
toolbar.animate().alpha(alpha)
|
||||||
.setListener(object: AnimatorListenerAdapter() {
|
.setListener(object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
toolbar.visibility = visibility
|
toolbar.visibility = visibility
|
||||||
animation.removeListener(this)
|
animation.removeListener(this)
|
||||||
|
@ -226,7 +245,7 @@ class ViewMediaActivity : BaseActivity(), ViewImageFragment.PhotoActionsListener
|
||||||
}
|
}
|
||||||
|
|
||||||
val attachment = attachments!![viewPager.currentItem].attachment
|
val attachment = attachments!![viewPager.currentItem].attachment
|
||||||
when(attachment.type) {
|
when (attachment.type) {
|
||||||
Attachment.Type.IMAGE -> shareImage(directory, attachment.url)
|
Attachment.Type.IMAGE -> shareImage(directory, attachment.url)
|
||||||
Attachment.Type.VIDEO,
|
Attachment.Type.VIDEO,
|
||||||
Attachment.Type.GIFV -> shareVideo(directory, attachment.url)
|
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) {
|
private fun shareImage(directory: File, url: String) {
|
||||||
|
isCreating = true
|
||||||
|
progressBarShare.visibility = View.VISIBLE
|
||||||
|
invalidateOptionsMenu()
|
||||||
val file = File(directory, getTemporaryMediaFilename("png"))
|
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 {
|
.subscribeOn(Schedulers.io())
|
||||||
val stream = FileOutputStream(file)
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
|
.doOnDispose {
|
||||||
stream.close()
|
futureTask.cancel(true)
|
||||||
} catch (fnfe: FileNotFoundException) {
|
|
||||||
Log.e(TAG, "Error writing temporary media.")
|
|
||||||
} catch (ioe: IOException) {
|
|
||||||
Log.e(TAG, "Error writing temporary media.")
|
|
||||||
}
|
}
|
||||||
}
|
.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) {
|
private fun shareVideo(directory: File, url: String) {
|
||||||
|
|
|
@ -21,10 +21,10 @@ 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.squareup.picasso.Picasso
|
|
||||||
|
|
||||||
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
import kotlinx.android.synthetic.main.item_autocomplete_account.view.*
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ class AccountSelectionAdapter(context: Context): ArrayAdapter<AccountEntity>(con
|
||||||
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)) {
|
if (!TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||||
Picasso.with(context)
|
Glide.with(avatar)
|
||||||
.load(account.profilePictureUrl)
|
.load(account.profilePictureUrl)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar)
|
.into(avatar)
|
||||||
|
|
|
@ -8,12 +8,12 @@ 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.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
class AccountViewHolder extends RecyclerView.ViewHolder {
|
class AccountViewHolder extends RecyclerView.ViewHolder {
|
||||||
private TextView username;
|
private TextView username;
|
||||||
|
@ -39,8 +39,7 @@ 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);
|
||||||
Context context = avatar.getContext();
|
Glide.with(avatar)
|
||||||
Picasso.with(context)
|
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.into(avatar);
|
||||||
|
|
|
@ -24,11 +24,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.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
public class BlocksAdapter extends AccountAdapter {
|
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 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);
|
||||||
Picasso.with(avatar.getContext())
|
Glide.with(avatar)
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.into(avatar);
|
||||||
|
|
|
@ -25,11 +25,11 @@ import android.widget.Filterable;
|
||||||
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.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -147,7 +147,7 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
||||||
account.getEmojis(), accountViewHolder.displayName);
|
account.getEmojis(), accountViewHolder.displayName);
|
||||||
accountViewHolder.displayName.setText(emojifiedName);
|
accountViewHolder.displayName.setText(emojifiedName);
|
||||||
if (!account.getAvatar().isEmpty()) {
|
if (!account.getAvatar().isEmpty()) {
|
||||||
Picasso.with(context)
|
Glide.with(accountViewHolder.avatar)
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(accountViewHolder.avatar);
|
.into(accountViewHolder.avatar);
|
||||||
|
@ -188,7 +188,7 @@ public class ComposeAutoCompleteAdapter extends BaseAdapter
|
||||||
emoji.getShortcode()
|
emoji.getShortcode()
|
||||||
);
|
);
|
||||||
emojiViewHolder.shortcode.setText(formattedShortcode);
|
emojiViewHolder.shortcode.setText(formattedShortcode);
|
||||||
Picasso.with(context)
|
Glide.with(emojiViewHolder.preview)
|
||||||
.load(emoji.getUrl())
|
.load(emoji.getUrl())
|
||||||
.into(emojiViewHolder.preview);
|
.into(emojiViewHolder.preview);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Emoji
|
import com.keylesspalace.tusky.entity.Emoji
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
|
|
||||||
class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener: OnEmojiSelectedListener) : RecyclerView.Adapter<EmojiAdapter.EmojiHolder>() {
|
class EmojiAdapter(emojiList: List<Emoji>, private val onEmojiSelectedListener: OnEmojiSelectedListener) : RecyclerView.Adapter<EmojiAdapter.EmojiHolder>() {
|
||||||
private val emojiList : List<Emoji>
|
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) {
|
override fun onBindViewHolder(viewHolder: EmojiAdapter.EmojiHolder, position: Int) {
|
||||||
val emoji = emojiList[position]
|
val emoji = emojiList[position]
|
||||||
|
|
||||||
Picasso.with(viewHolder.emojiImageView.context)
|
Glide.with(viewHolder.emojiImageView)
|
||||||
.load(emoji.url)
|
.load(emoji.url)
|
||||||
.into(viewHolder.emojiImageView)
|
.into(viewHolder.emojiImageView)
|
||||||
|
|
||||||
|
|
|
@ -24,11 +24,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.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
public class FollowRequestsAdapter extends AccountAdapter {
|
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 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);
|
||||||
Picasso.with(avatar.getContext())
|
Glide.with(avatar)
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.into(avatar);
|
||||||
|
|
|
@ -9,11 +9,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.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
public class MutesAdapter extends AccountAdapter {
|
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 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);
|
||||||
Picasso.with(avatar.getContext())
|
Glide.with(avatar)
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.into(avatar);
|
||||||
|
|
|
@ -33,6 +33,7 @@ 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;
|
||||||
|
@ -46,7 +47,6 @@ import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||||
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
import com.keylesspalace.tusky.viewdata.NotificationViewData;
|
||||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||||
import com.mikepenz.iconics.utils.Utils;
|
import com.mikepenz.iconics.utils.Utils;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -309,9 +309,8 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
if (TextUtils.isEmpty(account.getAvatar())) {
|
if (TextUtils.isEmpty(account.getAvatar())) {
|
||||||
avatar.setImageResource(R.drawable.avatar_default);
|
avatar.setImageResource(R.drawable.avatar_default);
|
||||||
} else {
|
} else {
|
||||||
Picasso.with(context)
|
Glide.with(avatar)
|
||||||
.load(account.getAvatar())
|
.load(account.getAvatar())
|
||||||
.fit()
|
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.into(avatar);
|
||||||
}
|
}
|
||||||
|
@ -487,12 +486,11 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
void setAvatars(@Nullable String statusAvatarUrl, @Nullable String notificationAvatarUrl) {
|
||||||
Context context = statusAvatar.getContext();
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(statusAvatarUrl)) {
|
if (TextUtils.isEmpty(statusAvatarUrl)) {
|
||||||
statusAvatar.setImageResource(R.drawable.avatar_default);
|
statusAvatar.setImageResource(R.drawable.avatar_default);
|
||||||
} else {
|
} else {
|
||||||
Picasso.with(context)
|
Glide.with(statusAvatar)
|
||||||
.load(statusAvatarUrl)
|
.load(statusAvatarUrl)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(statusAvatar);
|
.into(statusAvatar);
|
||||||
|
@ -501,7 +499,7 @@ public class NotificationsAdapter extends RecyclerView.Adapter {
|
||||||
if (TextUtils.isEmpty(notificationAvatarUrl)) {
|
if (TextUtils.isEmpty(notificationAvatarUrl)) {
|
||||||
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
notificationAvatar.setImageResource(R.drawable.avatar_default);
|
||||||
} else {
|
} else {
|
||||||
Picasso.with(context)
|
Glide.with(notificationAvatar)
|
||||||
.load(notificationAvatarUrl)
|
.load(notificationAvatarUrl)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(notificationAvatar);
|
.into(notificationAvatar);
|
||||||
|
|
|
@ -12,6 +12,7 @@ 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.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
import com.keylesspalace.tusky.entity.Attachment.Focus;
|
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.view.MediaPreviewImageView;
|
||||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||||
import com.mikepenz.iconics.utils.Utils;
|
import com.mikepenz.iconics.utils.Utils;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
@ -182,7 +182,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
if (TextUtils.isEmpty(url)) {
|
if (TextUtils.isEmpty(url)) {
|
||||||
avatar.setImageResource(R.drawable.avatar_default);
|
avatar.setImageResource(R.drawable.avatar_default);
|
||||||
} else {
|
} else {
|
||||||
Picasso.with(avatar.getContext())
|
Glide.with(avatar)
|
||||||
.load(url)
|
.load(url)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatar);
|
.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 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++) {
|
for (int i = 0; i < n; i++) {
|
||||||
String previewUrl = attachments.get(i).getPreviewUrl();
|
String previewUrl = attachments.get(i).getPreviewUrl();
|
||||||
String description = attachments.get(i).getDescription();
|
String description = attachments.get(i).getDescription();
|
||||||
|
@ -336,10 +333,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
mediaPreviews[i].setVisibility(View.VISIBLE);
|
mediaPreviews[i].setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
if (TextUtils.isEmpty(previewUrl)) {
|
if (TextUtils.isEmpty(previewUrl)) {
|
||||||
Picasso.with(context)
|
Glide.with(mediaPreviews[i])
|
||||||
.load(mediaPreviewUnloadedId)
|
.load(mediaPreviewUnloadedId)
|
||||||
.resize(maxW, maxH)
|
|
||||||
.onlyScaleDown()
|
|
||||||
.centerInside()
|
.centerInside()
|
||||||
.into(mediaPreviews[i]);
|
.into(mediaPreviews[i]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -349,23 +344,18 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
if (focus != null) { // If there is a focal point for this attachment:
|
if (focus != null) { // If there is a focal point for this attachment:
|
||||||
mediaPreviews[i].setFocalPoint(focus);
|
mediaPreviews[i].setFocalPoint(focus);
|
||||||
|
|
||||||
Picasso.with(context)
|
Glide.with(mediaPreviews[i])
|
||||||
.load(previewUrl)
|
.load(previewUrl)
|
||||||
.placeholder(mediaPreviewUnloadedId)
|
.placeholder(mediaPreviewUnloadedId)
|
||||||
.resize(maxW, maxH)
|
|
||||||
.onlyScaleDown()
|
|
||||||
.centerInside()
|
.centerInside()
|
||||||
// Also pass the mediaPreview as a callback to ensure it is called
|
.addListener(mediaPreviews[i])
|
||||||
// initially when the image gets loaded:
|
.into(mediaPreviews[i]);
|
||||||
.into(mediaPreviews[i], mediaPreviews[i]);
|
|
||||||
} else {
|
} else {
|
||||||
mediaPreviews[i].removeFocalPoint();
|
mediaPreviews[i].removeFocalPoint();
|
||||||
|
|
||||||
Picasso.with(context)
|
Glide.with(mediaPreviews[i])
|
||||||
.load(previewUrl)
|
.load(previewUrl)
|
||||||
.placeholder(mediaPreviewUnloadedId)
|
.placeholder(mediaPreviewUnloadedId)
|
||||||
.resize(maxW, maxH)
|
|
||||||
.onlyScaleDown()
|
|
||||||
.centerInside()
|
.centerInside()
|
||||||
.into(mediaPreviews[i]);
|
.into(mediaPreviews[i]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.bumptech.glide.Glide;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Card;
|
import com.keylesspalace.tusky.entity.Card;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
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.CustomURLSpan;
|
||||||
import com.keylesspalace.tusky.util.LinkHelper;
|
import com.keylesspalace.tusky.util.LinkHelper;
|
||||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -176,9 +176,8 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
|
|
||||||
cardView.setClipToOutline(true);
|
cardView.setClipToOutline(true);
|
||||||
|
|
||||||
Picasso.with(cardImage.getContext())
|
Glide.with(cardImage)
|
||||||
.load(card.getImage())
|
.load(card.getImage())
|
||||||
.fit()
|
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
.into(cardImage);
|
.into(cardImage);
|
||||||
|
|
||||||
|
|
|
@ -19,15 +19,14 @@ import android.content.Context;
|
||||||
import android.text.InputFilter;
|
import android.text.InputFilter;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
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.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||||
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
import com.keylesspalace.tusky.viewdata.StatusViewData;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
@ -55,7 +54,7 @@ public class StatusViewHolder extends StatusBaseViewHolder {
|
||||||
int padding = Utils.dpToPx(context, 12);
|
int padding = Utils.dpToPx(context, 12);
|
||||||
avatar.setPaddingRelative(0, 0, padding, padding);
|
avatar.setPaddingRelative(0, 0, padding, padding);
|
||||||
avatarInset.setVisibility(View.VISIBLE);
|
avatarInset.setVisibility(View.VISIBLE);
|
||||||
Picasso.with(context)
|
Glide.with(context)
|
||||||
.load(rebloggedUrl)
|
.load(rebloggedUrl)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.into(avatarInset);
|
.into(avatarInset);
|
||||||
|
|
|
@ -23,12 +23,12 @@ 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.adapter.StatusBaseViewHolder;
|
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder;
|
||||||
import com.keylesspalace.tusky.entity.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
import com.keylesspalace.tusky.util.SmartLengthInputFilter;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ public class ConversationViewHolder extends StatusBaseViewHolder {
|
||||||
for(int i=0; i < avatars.length; i++) {
|
for(int i=0; i < avatars.length; i++) {
|
||||||
ImageView avatarView = avatars[i];
|
ImageView avatarView = avatars[i];
|
||||||
if(i < accounts.size()) {
|
if(i < accounts.size()) {
|
||||||
Picasso.with(avatarView.getContext())
|
Glide.with(avatarView)
|
||||||
.load(accounts.get(i).getAvatar())
|
.load(accounts.get(i).getAvatar())
|
||||||
.into(avatarView);
|
.into(avatarView);
|
||||||
avatarView.setVisibility(View.VISIBLE);
|
avatarView.setVisibility(View.VISIBLE);
|
||||||
|
|
|
@ -27,6 +27,8 @@ import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
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.R
|
||||||
import com.keylesspalace.tusky.ViewMediaActivity
|
import com.keylesspalace.tusky.ViewMediaActivity
|
||||||
import com.keylesspalace.tusky.di.Injectable
|
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.util.show
|
||||||
import com.keylesspalace.tusky.view.SquareImageView
|
import com.keylesspalace.tusky.view.SquareImageView
|
||||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
import kotlinx.android.synthetic.main.fragment_timeline.*
|
import kotlinx.android.synthetic.main.fragment_timeline.*
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.Callback
|
import retrofit2.Callback
|
||||||
|
@ -82,7 +83,7 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
||||||
override fun onFailure(call: Call<List<Status>>?, t: Throwable?) {
|
override fun onFailure(call: Call<List<Status>>?, t: Throwable?) {
|
||||||
fetchingStatus = FetchingStatus.NOT_FETCHING
|
fetchingStatus = FetchingStatus.NOT_FETCHING
|
||||||
|
|
||||||
if(isAdded) {
|
if (isAdded) {
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
statusView.show()
|
statusView.show()
|
||||||
|
@ -102,7 +103,7 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
||||||
|
|
||||||
override fun onResponse(call: Call<List<Status>>, response: Response<List<Status>>) {
|
override fun onResponse(call: Call<List<Status>>, response: Response<List<Status>>) {
|
||||||
fetchingStatus = FetchingStatus.NOT_FETCHING
|
fetchingStatus = FetchingStatus.NOT_FETCHING
|
||||||
if(isAdded) {
|
if (isAdded) {
|
||||||
swipeRefreshLayout.isRefreshing = false
|
swipeRefreshLayout.isRefreshing = false
|
||||||
progressBar.visibility = View.GONE
|
progressBar.visibility = View.GONE
|
||||||
|
|
||||||
|
@ -302,13 +303,8 @@ class AccountMediaFragment : BaseFragment(), Injectable {
|
||||||
holder.imageView.setBackgroundColor(Color.HSVToColor(itemBgBaseHSV))
|
holder.imageView.setBackgroundColor(Color.HSVToColor(itemBgBaseHSV))
|
||||||
val item = items[position]
|
val item = items[position]
|
||||||
|
|
||||||
val maxW = holder.imageView.context.resources.getInteger(R.integer.media_max_width)
|
Glide.with(holder.imageView)
|
||||||
val maxH = holder.imageView.context.resources.getInteger(R.integer.media_max_height)
|
|
||||||
|
|
||||||
Picasso.with(holder.imageView.context)
|
|
||||||
.load(item.attachment.previewUrl)
|
.load(item.attachment.previewUrl)
|
||||||
.resize(maxW, maxH)
|
|
||||||
.onlyScaleDown()
|
|
||||||
.centerInside()
|
.centerInside()
|
||||||
.into(holder.imageView)
|
.into(holder.imageView)
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,21 +18,24 @@ package com.keylesspalace.tusky.fragment
|
||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
import android.animation.AnimatorListenerAdapter
|
import android.animation.AnimatorListenerAdapter
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
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.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
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.github.chrisbanes.photoview.PhotoViewAttacher
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.entity.Attachment
|
import com.keylesspalace.tusky.entity.Attachment
|
||||||
import com.keylesspalace.tusky.util.hide
|
import com.keylesspalace.tusky.util.hide
|
||||||
import com.keylesspalace.tusky.util.visible
|
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.activity_view_media.*
|
||||||
import kotlinx.android.synthetic.main.fragment_view_image.*
|
import kotlinx.android.synthetic.main.fragment_view_image.*
|
||||||
|
|
||||||
|
@ -46,7 +49,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
private lateinit var attacher: PhotoViewAttacher
|
private lateinit var attacher: PhotoViewAttacher
|
||||||
private lateinit var photoActionsListener: PhotoActionsListener
|
private lateinit var photoActionsListener: PhotoActionsListener
|
||||||
private lateinit var toolbar: View
|
private lateinit var toolbar: View
|
||||||
override lateinit var descriptionView : TextView
|
override lateinit var descriptionView: TextView
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
|
@ -74,53 +77,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
val maxW = photoView.context.resources.getInteger(R.integer.media_max_width)
|
loadImageFromNetwork(url, photoView)
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
@ -134,7 +91,7 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
val arguments = this.arguments!!
|
val arguments = this.arguments!!
|
||||||
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
val attachment = arguments.getParcelable<Attachment>(ARG_ATTACHMENT)
|
||||||
val url: String?
|
val url: String?
|
||||||
var description : String? = null
|
var description: String? = null
|
||||||
|
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
url = attachment.url
|
url = attachment.url
|
||||||
|
@ -169,35 +126,53 @@ class ViewImageFragment : ViewMediaFragment() {
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetach() {
|
override fun onDestroyView() {
|
||||||
super.onDetach()
|
Glide.with(this).clear(photoView)
|
||||||
Picasso.with(context).cancelRequest(photoView)
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadImageFromNetwork(url: String, photoView: ImageView) {
|
private fun loadImageFromNetwork(url: String, photoView: ImageView) =
|
||||||
val maxW = photoView.context.resources.getInteger(R.integer.media_max_width)
|
//Request image from the any cache
|
||||||
val maxH = photoView.context.resources.getInteger(R.integer.media_max_height)
|
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() {
|
private fun completeTransition() {
|
||||||
progressBar?.hide()
|
|
||||||
attacher.update()
|
attacher.update()
|
||||||
photoActionsListener.onBringUp()
|
photoActionsListener.onBringUp()
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,12 +23,12 @@ import android.os.Bundle
|
||||||
import android.service.chooser.ChooserTarget
|
import android.service.chooser.ChooserTarget
|
||||||
import android.service.chooser.ChooserTargetService
|
import android.service.chooser.ChooserTargetService
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.TuskyApplication
|
import com.keylesspalace.tusky.TuskyApplication
|
||||||
import com.keylesspalace.tusky.db.AccountManager
|
import com.keylesspalace.tusky.db.AccountManager
|
||||||
import com.keylesspalace.tusky.di.Injectable
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.util.NotificationHelper
|
import com.keylesspalace.tusky.util.NotificationHelper
|
||||||
import com.squareup.picasso.Picasso
|
|
||||||
|
|
||||||
|
|
||||||
@TargetApi(23)
|
@TargetApi(23)
|
||||||
|
@ -48,10 +48,13 @@ class AccountChooserService : ChooserTargetService(), Injectable {
|
||||||
val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) {
|
val icon: Icon = if (TextUtils.isEmpty(account.profilePictureUrl)) {
|
||||||
Icon.createWithResource(applicationContext, R.drawable.avatar_default)
|
Icon.createWithResource(applicationContext, R.drawable.avatar_default)
|
||||||
} else {
|
} else {
|
||||||
Icon.createWithBitmap(Picasso.with(this).load(account.profilePictureUrl)
|
val bmp = Glide.with(this)
|
||||||
|
.asBitmap()
|
||||||
|
.load(account.profilePictureUrl)
|
||||||
.error(R.drawable.avatar_default)
|
.error(R.drawable.avatar_default)
|
||||||
.placeholder(R.drawable.avatar_default)
|
.placeholder(R.drawable.avatar_default)
|
||||||
.get())
|
.submit()
|
||||||
|
Icon.createWithBitmap(bmp.get())
|
||||||
}
|
}
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id)
|
bundle.putLong(NotificationHelper.ACCOUNT_ID, account.id)
|
||||||
|
|
|
@ -20,23 +20,26 @@ import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.drawable.BitmapDrawable;
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import android.text.SpannableStringBuilder;
|
import android.text.SpannableStringBuilder;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
import android.text.SpannedString;
|
import android.text.SpannedString;
|
||||||
import android.text.style.ReplacementSpan;
|
import android.text.style.ReplacementSpan;
|
||||||
import android.view.View;
|
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.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
import com.squareup.picasso.Target;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
public class CustomEmojiHelper {
|
public class CustomEmojiHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,13 +58,13 @@ public class CustomEmojiHelper {
|
||||||
CharSequence pattern = new StringBuilder(":").append(emoji.getShortcode()).append(':');
|
CharSequence pattern = new StringBuilder(":").append(emoji.getShortcode()).append(':');
|
||||||
Matcher matcher = Pattern.compile(pattern.toString()).matcher(text);
|
Matcher matcher = Pattern.compile(pattern.toString()).matcher(text);
|
||||||
while (matcher.find()) {
|
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);
|
EmojiSpan span = new EmojiSpan(view);
|
||||||
builder.setSpan(span, matcher.start(), matcher.end(), 0);
|
builder.setSpan(span, matcher.start(), matcher.end(), 0);
|
||||||
Picasso.with(view.getContext())
|
Glide.with(view)
|
||||||
|
.asBitmap()
|
||||||
.load(emoji.getUrl())
|
.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 @Nullable Drawable imageDrawable;
|
||||||
private WeakReference<View> viewWeakReference;
|
private WeakReference<View> viewWeakReference;
|
||||||
|
@ -118,20 +121,23 @@ public class CustomEmojiHelper {
|
||||||
canvas.restore();
|
canvas.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
Target<Bitmap> getTarget(){
|
||||||
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
|
return new CustomTarget<Bitmap>() {
|
||||||
View view = viewWeakReference.get();
|
@Override
|
||||||
if(view != null) {
|
public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) {
|
||||||
imageDrawable = new BitmapDrawable(view.getContext().getResources(), bitmap);
|
View view = viewWeakReference.get();
|
||||||
view.invalidate();
|
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
|
package com.keylesspalace.tusky.util
|
||||||
|
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
import android.widget.ImageView
|
|
||||||
|
|
||||||
import com.keylesspalace.tusky.entity.Attachment.Focus
|
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
|
* 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,
|
fun calculateScaling(viewWidth: Float, viewHeight: Float,
|
||||||
imageWidth: Float, imageHeight: Float): Float {
|
imageWidth: Float, imageHeight: Float): Float {
|
||||||
if (isVerticalCrop(viewWidth, viewHeight, imageWidth, imageHeight)) {
|
return if (isVerticalCrop(viewWidth, viewHeight, imageWidth, imageHeight)) {
|
||||||
return viewWidth / imageWidth
|
viewWidth / imageWidth
|
||||||
} else { // horizontal crop:
|
} else { // horizontal crop:
|
||||||
return viewHeight / imageHeight
|
viewHeight / imageHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,9 @@ import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.text.BidiFormatter;
|
import androidx.core.text.BidiFormatter;
|
||||||
import android.util.Log;
|
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.JobManager;
|
||||||
import com.evernote.android.job.JobRequest;
|
import com.evernote.android.job.JobRequest;
|
||||||
import com.keylesspalace.tusky.BuildConfig;
|
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.entity.Status;
|
||||||
import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver;
|
import com.keylesspalace.tusky.receiver.NotificationClearBroadcastReceiver;
|
||||||
import com.keylesspalace.tusky.receiver.SendStatusBroadcastReceiver;
|
import com.keylesspalace.tusky.receiver.SendStatusBroadcastReceiver;
|
||||||
import com.keylesspalace.tusky.view.RoundedTransformation;
|
|
||||||
import com.squareup.picasso.Picasso;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
public class NotificationHelper {
|
public class NotificationHelper {
|
||||||
|
|
||||||
|
@ -169,11 +170,14 @@ public class NotificationHelper {
|
||||||
//load the avatar synchronously
|
//load the avatar synchronously
|
||||||
Bitmap accountAvatar;
|
Bitmap accountAvatar;
|
||||||
try {
|
try {
|
||||||
accountAvatar = Picasso.with(context)
|
FutureTarget<Bitmap> target = Glide.with(context)
|
||||||
|
.asBitmap()
|
||||||
.load(body.getAccount().getAvatar())
|
.load(body.getAccount().getAvatar())
|
||||||
.transform(new RoundedTransformation(20))
|
.transform(new RoundedCorners(20))
|
||||||
.get();
|
.submit();
|
||||||
} catch (IOException e) {
|
|
||||||
|
accountAvatar = target.get();
|
||||||
|
} catch (ExecutionException | InterruptedException e) {
|
||||||
Log.d(TAG, "error loading account avatar", e);
|
Log.d(TAG, "error loading account avatar", e);
|
||||||
accountAvatar = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar_default);
|
accountAvatar = BitmapFactory.decodeResource(context.getResources(), R.drawable.avatar_default);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,12 +16,16 @@ package com.keylesspalace.tusky.view
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.Matrix
|
import android.graphics.Matrix
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.appcompat.widget.AppCompatImageView
|
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.entity.Attachment
|
||||||
|
|
||||||
import com.keylesspalace.tusky.util.FocalPointUtil
|
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
|
* This is an extension of the standard android ImageView, which makes sure to update the custom
|
||||||
|
@ -39,7 +43,7 @@ class MediaPreviewImageView
|
||||||
context: Context,
|
context: Context,
|
||||||
attrs: AttributeSet? = null,
|
attrs: AttributeSet? = null,
|
||||||
defStyleAttr: Int = 0
|
defStyleAttr: Int = 0
|
||||||
) : AppCompatImageView(context, attrs, defStyleAttr), Callback {
|
) : AppCompatImageView(context, attrs, defStyleAttr),RequestListener<Drawable> {
|
||||||
private var focus: Attachment.Focus? = null
|
private var focus: Attachment.Focus? = null
|
||||||
private var focalMatrix: Matrix? = null
|
private var focalMatrix: Matrix? = null
|
||||||
|
|
||||||
|
@ -94,18 +98,16 @@ defStyleAttr: Int = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
|
||||||
* Called when the image is first succesfully loaded by Picasso, this function makes sure
|
return false
|
||||||
* that the custom matrix of this image is initialized if a focus point is set.
|
|
||||||
*/
|
|
||||||
override fun onSuccess() {
|
|
||||||
onSizeChanged(width, height, width, height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not handle the error here, instead it will be handled higher up the call chain.
|
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
|
||||||
override fun onError() {
|
onSizeChanged(width, height, width, height)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the size of the view changes, it calls the FocalPointUtil to update the
|
* 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.
|
* 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_marginStart="12dp"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
license:license="@string/license_apache_2"
|
license:license="@string/license_apache_2"
|
||||||
license:link="https://square.github.io/picasso/"
|
license:link="https://bumptech.github.io/glide/"
|
||||||
license:name="Picasso" />
|
license:name="Glide" />
|
||||||
|
|
||||||
<com.keylesspalace.tusky.view.LicenseCard
|
<com.keylesspalace.tusky.view.LicenseCard
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -17,4 +17,12 @@
|
||||||
android:background="@color/toolbar_view_media"
|
android:background="@color/toolbar_view_media"
|
||||||
android:theme="@style/AppTheme.Account.AppBarLayout"/>
|
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>
|
</FrameLayout>
|
|
@ -16,10 +16,6 @@ class FakeTuskyApplication : TuskyApplication() {
|
||||||
// No-op
|
// No-op
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initPicasso() {
|
|
||||||
// No-op
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getServiceLocator(): ServiceLocator {
|
override fun getServiceLocator(): ServiceLocator {
|
||||||
return locator
|
return locator
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue