improved profile image on pre-lollipop devices

added sponsors in README
This commit is contained in:
Mariotaku Lee 2017-03-07 17:22:02 +08:00
parent d7e107c126
commit c52aa2da68
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
39 changed files with 324 additions and 344 deletions

View File

@ -62,11 +62,11 @@ Bitcoin: `1FHAVAzge7cj1LfCTMfnLL49DgA3mVUCuW`
**Donators**
[@TwidereProject/donators](https://twitter.com/TwidereProject/lists/donators), if you haven't find your name, please contact @TwidereProject :)
Checkout enhanced features on Google Play!
Buy me a ~~bread~~ [game](http://steamcommunity.com/id/mariotaku/wishlist) or anything you want :)
**Sponsors**
[帮我支付宝账户里随便加点钱](https://twitter.com/xmxsuperstar/status/724094631621750785)
<a href='http://www.sujitech.com/'><img src='resources/logos/sujitech_logo.png'/></a>
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -40,7 +40,7 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.AccountDetails;
import org.mariotaku.twidere.model.util.AccountUtils;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaPreloader;
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper;
import javax.inject.Inject;
@ -94,10 +94,10 @@ public abstract class AccountsListPreference extends TintedPreferenceCategory im
private final SharedPreferences mSwitchPreference;
@Inject
MediaLoaderWrapper mImageLoader;
MediaPreloader mediaPreloader;
public AccountItemPreference(final Context context, final AccountDetails account,
@Nullable final String switchKey, final boolean switchDefault) {
@Nullable final String switchKey, final boolean switchDefault) {
super(context);
GeneralComponentHelper.build(context).inject(this);
final String switchPreferenceName = ACCOUNT_PREFERENCES_NAME_PREFIX + account.key;
@ -122,7 +122,7 @@ public abstract class AccountsListPreference extends TintedPreferenceCategory im
super.onBindViewHolder(holder);
final View iconView = holder.findViewById(android.R.id.icon);
if (iconView instanceof PreferenceImageView) {
final PreferenceImageView imageView = (PreferenceImageView) iconView;
final ImageView imageView = (ImageView) iconView;
final int maxSize = getContext().getResources().getDimensionPixelSize(R.dimen.element_size_normal);
imageView.setMinimumWidth(maxSize);
imageView.setMinimumHeight(maxSize);

View File

@ -1,156 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util.media
import android.media.MediaPlayer
import android.media.MediaPlayer.*
/**
* From https://gist.github.com/danielhawkes/1029568
*
* A wrapper class for [android.media.MediaPlayer].
*
* Encapsulates an instance of MediaPlayer, and makes a record of its internal state accessible via a
* [MediaPlayerWrapper.getState] accessor. Most of the frequently used methods are available, but some still
* need adding.
*
*/
class MediaPlayerWrapper(val player: MediaPlayer) {
var state: State = State.IDLE
private set
var onPreparedListener: OnPreparedListener? = null
var onCompletionListener: OnCompletionListener? = null
var onBufferingUpdateListener: OnBufferingUpdateListener? = null
var onErrorListener: OnErrorListener? = null
var onInfoListener: OnInfoListener? = null
init {
player.setOnPreparedListener { mp ->
state = State.PREPARED
onPreparedListener?.onPrepared(mp)
}
player.setOnCompletionListener { mp ->
state = State.PLAYBACK_COMPLETE
onCompletionListener?.onCompletion(mp)
}
player.setOnBufferingUpdateListener { mp, percent ->
onBufferingUpdateListener?.onBufferingUpdate(mp, percent)
}
player.setOnErrorListener { mp, what, extra ->
state = State.ERROR
return@setOnErrorListener onErrorListener?.onError(mp, what, extra) ?: false
}
player.setOnInfoListener { mp, what, extra ->
return@setOnInfoListener onInfoListener?.onInfo(mp, what, extra) ?: false
}
}
fun setDataSource(path: String) {
if (!state.canSetDataSource) throw illegalState()
player.setDataSource(path)
state = State.INITIALIZED
}
fun prepareAsync() {
if (!state.canPrepare) throw illegalState()
player.prepareAsync()
state = State.PREPARING
}
val isPlaying: Boolean
get() = state.canAccessInfo && player.isPlaying
fun seekTo(msec: Int) {
if (!state.canAccessInfo) throw illegalState()
player.seekTo(msec)
}
fun pause() {
if (!state.canPause) throw illegalState()
player.pause()
state = State.PAUSED
throw illegalState()
}
fun start() {
if (!state.canOperate) throw illegalState()
player.start()
state = State.STARTED
}
fun stop() {
if (!state.canOperate) throw illegalState()
player.stop()
state = State.STOPPED
throw illegalState()
}
fun reset() {
player.reset()
state = State.IDLE
}
fun release() {
player.release()
}
fun setVolume(leftVolume: Float, rightVolume: Float) {
if (!state.canOperate) throw illegalState()
player.setVolume(leftVolume, rightVolume)
}
val currentPosition: Int
get() {
if (!state.canAccessInfo) throw illegalState()
return player.currentPosition
}
val duration: Int
get() {
if (!state.canAccessInfo) throw illegalState()
return player.duration
}
private fun illegalState(): Throwable {
throw IllegalStateException("Illegal state $state")
}
/* METHOD WRAPPING FOR STATE CHANGES */
enum class State(
val canPrepare: Boolean = false,
val canOperate: Boolean = false,
val canPause: Boolean = false,
val canAccessInfo: Boolean = false,
val canSetDataSource: Boolean = false
) {
IDLE(canSetDataSource = true),
ERROR(),
INITIALIZED(canPrepare = true),
PREPARING(),
PREPARED(canAccessInfo = true, canOperate = true),
STARTED(canAccessInfo = true, canOperate = true, canPause = true),
STOPPED(canAccessInfo = true, canPrepare = true),
PLAYBACK_COMPLETE(canAccessInfo = true, canOperate = true),
PAUSED(canAccessInfo = true, canOperate = true, canPause = true)
}
}

View File

@ -163,10 +163,18 @@ public class ShapedImageView extends AppCompatImageView {
mCornerRadius = radius;
}
public float getCornerRadius() {
return mCornerRadius;
}
public void setCornerRadiusRatio(float ratio) {
mCornerRadiusRatio = ratio;
}
public float getCornerRadiusRatio() {
return mCornerRadiusRatio;
}
public void setDrawShadow(final boolean drawShadow) {
mDrawShadow = drawShadow;
}

View File

@ -1,58 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view.holder;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.view.iface.IColorLabelView;
public class AccountViewHolder {
public final ImageView profileImage;
public final TextView name, screenName;
public final CompoundButton toggle;
public final View toggleContainer;
public final ImageView accountType;
private final IColorLabelView content;
private final View dragHandle;
public AccountViewHolder(final View view) {
content = (IColorLabelView) view;
name = (TextView) view.findViewById(android.R.id.text1);
screenName = (TextView) view.findViewById(android.R.id.text2);
profileImage = (ImageView) view.findViewById(android.R.id.icon);
toggle = (CompoundButton) view.findViewById(android.R.id.toggle);
toggleContainer = view.findViewById(R.id.toggle_container);
dragHandle = view.findViewById(R.id.drag_handle);
accountType = (ImageView) view.findViewById(R.id.account_type);
}
public void setAccountColor(final int color) {
content.drawEnd(color);
}
public void setSortEnabled(boolean enabled) {
dragHandle.setVisibility(enabled ? View.VISIBLE : View.GONE);
}
}

View File

@ -91,8 +91,8 @@ class AccountSelectorActivity : BaseActivity(), OnItemClickListener {
setContentView(R.layout.activity_account_selector)
DataStoreUtils.prepareDatabase(this)
adapter = AccountDetailsAdapter(this, Glide.with(this)).apply {
setSwitchEnabled(!isSingleSelection)
setSortEnabled(false)
switchEnabled = !isSingleSelection
sortEnabled = false
val am = AccountManager.get(context)
val allAccountDetails = AccountUtils.getAllAccountDetails(am, AccountUtils.getAccounts(am), false)
val extraKeys = onlyIncludeKeys

View File

@ -463,7 +463,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
if (accounts.size == 1) {
accountsCount.setText(null)
val account = accounts[0]
Glide.with(this).loadProfileImage(this, account).into(accountProfileImage)
val profileImageStyle = preferences[profileImageStyleKey]
Glide.with(this).loadProfileImage(this, account, profileImageStyle).into(accountProfileImage)
accountProfileImage.setBorderColor(account.color)
} else {
accountsCount.setText(accounts.size.toString())
@ -1424,7 +1425,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
itemView.alpha = if (isSelected) 1f else 0.33f
(itemView as CheckableLinearLayout).isChecked = isSelected
val context = adapter.context
adapter.requestManager.loadProfileImage(context, account).into(iconView)
adapter.requestManager.loadProfileImage(context, account, adapter.profileImageStyle).into(iconView)
iconView.setBorderColor(account.color)
nameView.text = if (adapter.isNameFirst) account.user.name else "@" + account.user.screen_name
}

View File

@ -50,6 +50,7 @@ import org.mariotaku.twidere.constant.IntentConstants.EXTRA_ACCOUNT_KEY
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.ACTION_NAVIGATION_BACK
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION
import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.constant.profileImageStyleKey
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.SuggestionItem
@ -264,6 +265,7 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
private val activity: QuickSearchBarActivity
) : CursorAdapter(activity, null, 0), OnClickListener {
private val profileImageStyle = activity.preferences[profileImageStyleKey]
private val requestManager = Glide.with(activity)
private val inflater = LayoutInflater.from(activity)
private val userColorNameManager = activity.userColorNameManager
@ -320,7 +322,8 @@ class QuickSearchBarActivity : BaseActivity(), OnClickListener, LoaderCallbacks<
holder.text2.visibility = View.VISIBLE
holder.text2.text = "@${cursor.getString(indices.summary)}"
holder.icon.clearColorFilter()
requestManager.loadProfileImage(context, cursor.getString(indices.icon)).into(holder.icon)
requestManager.loadProfileImage(context, cursor.getString(indices.icon),
profileImageStyle).into(holder.icon)
}
VIEW_TYPE_USER_SCREEN_NAME -> {
val holder = view.tag as UserViewHolder

View File

@ -20,15 +20,14 @@
package org.mariotaku.twidere.adapter
import android.content.Context
import android.support.v7.widget.RecyclerViewAccessor
import android.view.View
import android.view.ViewGroup
import android.widget.CompoundButton
import com.bumptech.glide.RequestManager
import org.mariotaku.twidere.R
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
import org.mariotaku.twidere.view.holder.AccountViewHolder
@ -37,11 +36,19 @@ class AccountDetailsAdapter(
requestManager: RequestManager
) : BaseArrayAdapter<AccountDetails>(context, R.layout.list_item_account, requestManager = requestManager) {
private var sortEnabled: Boolean = false
private var switchEnabled: Boolean = false
var sortEnabled: Boolean = false
set(value) {
field = value
notifyDataSetChanged()
}
var switchEnabled: Boolean = false
set(value) {
field = value
notifyDataSetChanged()
}
var accountToggleListener: ((Int, Boolean) -> Unit)? = null
private val checkedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val checkedChangeListener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
val position = buttonView.tag as? Int ?: return@OnCheckedChangeListener
accountToggleListener?.invoke(position, isChecked)
}
@ -53,26 +60,13 @@ class AccountDetailsAdapter(
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val view = super.getView(position, convertView, parent)
val holder = view.tag as? AccountViewHolder ?: run {
val h = AccountViewHolder(view)
val h = AccountViewHolder(view, this)
view.tag = h
return@run h
}
RecyclerViewAccessor.setLayoutPosition(holder, position)
val details = getItem(position)
holder.name.text = details.user.name
holder.screenName.text = String.format("@%s", details.user.screen_name)
holder.setAccountColor(details.color)
if (profileImageEnabled) {
requestManager.loadProfileImage(context, details).into(holder.profileImage)
} else {
// TODO: display stub image?
}
val accountType = details.type
holder.accountType.setImageResource(AccountUtils.getAccountTypeIcon(accountType))
holder.toggle.isChecked = details.activated
holder.toggle.setOnCheckedChangeListener(checkedChangeListener)
holder.toggle.tag = position
holder.toggleContainer.visibility = if (switchEnabled) View.VISIBLE else View.GONE
holder.setSortEnabled(sortEnabled)
holder.display(details)
return view
}
@ -84,18 +78,6 @@ class AccountDetailsAdapter(
return getItem(position).key.hashCode().toLong()
}
fun setSwitchEnabled(enabled: Boolean) {
if (switchEnabled == enabled) return
switchEnabled = enabled
notifyDataSetChanged()
}
fun setSortEnabled(sortEnabled: Boolean) {
if (this.sortEnabled == sortEnabled) return
this.sortEnabled = sortEnabled
notifyDataSetChanged()
}
fun drop(from: Int, to: Int) {
val fromItem = getItem(from)
removeAt(from)

View File

@ -69,7 +69,7 @@ class AccountsSpinnerAdapter(
if (profileImageEnabled) {
icon.visibility = View.VISIBLE
icon.style = profileImageStyle
requestManager.loadProfileImage(context, item.user).into(icon)
requestManager.loadProfileImage(context, item.user, profileImageStyle).into(icon)
} else {
icon.visibility = View.GONE
}

View File

@ -35,7 +35,6 @@ import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.model.SuggestionItem
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.provider.TwidereDataStore.Suggestions
import org.mariotaku.twidere.util.MediaLoaderWrapper
import org.mariotaku.twidere.util.SharedPreferencesWrapper
import org.mariotaku.twidere.util.UserColorNameManager
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
@ -77,7 +76,7 @@ class ComposeAutoCompleteAdapter(context: Context, val requestManager: RequestMa
text2.text = String.format("@%s", cursor.getString(indices.summary))
if (displayProfileImage) {
val profileImageUrl = cursor.getString(indices.icon)
requestManager.loadProfileImage(context, profileImageUrl).into(icon)
requestManager.loadProfileImage(context, profileImageUrl, profileImageStyle).into(icon)
} else {
//TODO cancel image load
}

View File

@ -84,7 +84,7 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
@Inject
lateinit internal var extraFeaturesService: ExtraFeaturesService
@Inject
lateinit internal var mediaLoader: MediaLoaderWrapper
lateinit internal var mediaPreloader: MediaPreloader
@Inject
lateinit internal var contentNotificationManager: ContentNotificationManager
@ -250,7 +250,7 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
(mediaDownloader as TwidereMediaDownloader).reloadConnectivitySettings()
}
KEY_MEDIA_PRELOAD, KEY_PRELOAD_WIFI_ONLY -> {
mediaLoader.reloadOptions(preferences)
mediaPreloader.reloadOptions(preferences)
}
KEY_NAME_FIRST, KEY_I_WANT_MY_STARS_BACK -> {
contentNotificationManager.updatePreferences()

View File

@ -31,15 +31,17 @@ import org.mariotaku.twidere.extension.model.getBestProfileBanner
import org.mariotaku.twidere.extension.model.user
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.glide.RoundedRectTransformation
import org.mariotaku.twidere.view.ShapedImageView
fun RequestManager.loadProfileImage(
context: Context,
url: String?,
@ImageShapeStyle style: Int = ImageShapeStyle.SHAPE_CIRCLE,
@ImageShapeStyle style: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null
): DrawableRequestBuilder<String?> {
return configureLoadProfileImage(context, style) {
return configureLoadProfileImage(context, style, cornerRadius, cornerRadiusRatio) {
if (url == null || size == null) {
return@configureLoadProfileImage load(url)
} else {
@ -49,24 +51,28 @@ fun RequestManager.loadProfileImage(
}
fun RequestManager.loadProfileImage(context: Context, resourceId: Int,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE): DrawableRequestBuilder<Int> {
return configureLoadProfileImage(context, shapeStyle) { load(resourceId) }
@ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<Int> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { load(resourceId) }
}
fun RequestManager.loadProfileImage(context: Context, account: AccountDetails,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
@ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null): DrawableRequestBuilder<String?> {
return loadProfileImage(context, account.user, shapeStyle, size)
return loadProfileImage(context, account.user, shapeStyle, cornerRadius, cornerRadiusRatio, size)
}
fun RequestManager.loadProfileImage(context: Context, user: ParcelableUser,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
@ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null): DrawableRequestBuilder<String?> {
if (user.extras != null && user.extras.profile_image_url_fallback == null) {
// No fallback image, use compatible logic
return loadProfileImage(context, user.profile_image_url, shapeStyle, size)
return loadProfileImage(context, user.profile_image_url, shapeStyle, cornerRadius,
cornerRadiusRatio, size)
}
return configureLoadProfileImage(context, shapeStyle) {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
if (size != null) {
return@configureLoadProfileImage load(Utils.getTwitterProfileImageOfSize(user.profile_image_url, size))
} else {
@ -76,55 +82,70 @@ fun RequestManager.loadProfileImage(context: Context, user: ParcelableUser,
}
fun RequestManager.loadProfileImage(context: Context, userList: ParcelableUserList,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE): DrawableRequestBuilder<String?> {
return configureLoadProfileImage(context, shapeStyle) { load(userList.user_profile_image_url) }
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<String?> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(userList.user_profile_image_url)
}
}
fun RequestManager.loadProfileImage(context: Context, group: ParcelableGroup,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE): DrawableRequestBuilder<String?> {
return configureLoadProfileImage(context, shapeStyle) { load(group.homepage_logo) }
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<String?> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(group.homepage_logo)
}
}
fun RequestManager.loadProfileImage(context: Context, status: ParcelableStatus,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
@ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null): DrawableRequestBuilder<String?> {
if (status.extras != null && status.extras.user_profile_image_url_fallback == null) {
// No fallback image, use compatible logic
return loadProfileImage(context, status.user_profile_image_url, shapeStyle, size)
return loadProfileImage(context, status.user_profile_image_url, shapeStyle, cornerRadius,
cornerRadiusRatio, size)
}
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(status.user_profile_image_url)
}
return configureLoadProfileImage(context, shapeStyle) { load(status.user_profile_image_url) }
}
fun RequestManager.loadProfileImage(context: Context, conversation: ParcelableMessageConversation,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE,
@ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null): DrawableRequestBuilder<*> {
if (conversation.conversation_type == ParcelableMessageConversation.ConversationType.ONE_TO_ONE) {
val user = conversation.user
if (user != null) {
return loadProfileImage(context, user, shapeStyle, size)
return loadProfileImage(context, user, shapeStyle, cornerRadius, cornerRadiusRatio, size)
} else {
// TODO: show default conversation icon
return loadProfileImage(context, org.mariotaku.twidere.R.drawable.ic_profile_image_default_group)
return loadProfileImage(context, R.drawable.ic_profile_image_default_group, shapeStyle)
}
} else {
return loadProfileImage(context, conversation.conversation_avatar, shapeStyle, size)
.placeholder(R.drawable.ic_profile_image_default_group)
return loadProfileImage(context, conversation.conversation_avatar, shapeStyle, cornerRadius,
cornerRadiusRatio, size).placeholder(R.drawable.ic_profile_image_default_group)
}
}
fun RequestManager.loadOriginalProfileImage(context: Context, user: ParcelableUser,
@ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE): DrawableRequestBuilder<String> {
@ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f
): DrawableRequestBuilder<String> {
val original = user.extras.profile_image_url_original?.takeUnless(String::isEmpty)
?: Utils.getOriginalTwitterProfileImage(user.profile_image_url)
return configureLoadProfileImage(context, shapeStyle) { load(original) }
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(original)
}
}
fun RequestManager.loadProfileBanner(context: Context, user: ParcelableUser, width: Int): DrawableTypeRequest<String?> {
return load(user.getBestProfileBanner(width))
}
internal inline fun <T> configureLoadProfileImage(context: Context, shapeStyle: Int,
create: () -> DrawableTypeRequest<T>): DrawableRequestBuilder<T> {
internal inline fun <T> configureLoadProfileImage(context: Context, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, create: () -> DrawableTypeRequest<T>
): DrawableRequestBuilder<T> {
val builder = create()
builder.diskCacheStrategy(DiskCacheStrategy.RESULT)
builder.dontAnimate()
@ -134,6 +155,8 @@ internal inline fun <T> configureLoadProfileImage(context: Context, shapeStyle:
builder.bitmapTransform(CropCircleTransformation(context))
}
ImageShapeStyle.SHAPE_RECTANGLE -> {
builder.bitmapTransform(RoundedRectTransformation(context, cornerRadius,
cornerRadiusRatio))
}
}
}

View File

@ -451,7 +451,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
//TODO complete border color
clickedColors = clickedImageView.borderColors
val oldSelectedAccount = accountsAdapter.selectedAccount ?: return
Glide.with(this@AccountsDashboardFragment).loadProfileImage(context, oldSelectedAccount)
val profileImageStyle = preferences[profileImageStyleKey]
Glide.with(this@AccountsDashboardFragment).loadProfileImage(context, oldSelectedAccount,
profileImageStyle, clickedImageView.cornerRadius, clickedImageView.cornerRadiusRatio)
.into(clickedImageView).onLoadStarted(profileDrawable)
//TODO complete border color
clickedImageView.setBorderColors(*profileImageView.borderColors)
@ -510,8 +512,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
val account = accountsAdapter.selectedAccount ?: return
accountProfileNameView.text = account.user.name
accountProfileScreenNameView.text = "@${account.user.screen_name}"
Glide.with(this).loadProfileImage(context, account, size = ProfileImageSize.REASONABLY_SMALL)
.placeholder(profileImageSnapshot).into(accountProfileImageView)
Glide.with(this).loadProfileImage(context, account, preferences[profileImageStyleKey],
accountProfileImageView.cornerRadius, accountProfileImageView.cornerRadiusRatio,
ProfileImageSize.REASONABLY_SMALL).placeholder(profileImageSnapshot).into(accountProfileImageView)
//TODO complete border color
accountProfileImageView.setBorderColors(account.color)
accountProfileBanner.showNext()
@ -609,6 +612,7 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
init {
itemView.setOnClickListener(this)
iconView = itemView.findViewById(android.R.id.icon) as ShapedImageView
iconView.style = adapter.profileImageStyle
}
override fun onClick(v: View) {
@ -617,7 +621,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks<AccountsInfo>,
fun display(account: AccountDetails) {
iconView.setBorderColor(account.color)
adapter.requestManager.loadProfileImage(itemView.context, account).into(iconView)
adapter.requestManager.loadProfileImage(itemView.context, account,
adapter.profileImageStyle, iconView.cornerRadius,
iconView.cornerRadiusRatio).into(iconView)
}
}

View File

@ -61,8 +61,8 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks<Li
setHasOptionsMenu(true)
val am = AccountManager.get(context)
adapter = AccountDetailsAdapter(context, Glide.with(this)).apply {
setSortEnabled(true)
setSwitchEnabled(true)
sortEnabled = true
switchEnabled = true
accountToggleListener = { pos, checked ->
val item = getItem(pos)
item.activated = checked

View File

@ -929,7 +929,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
itemView.name.screenName = String.format("@%s", status.user_screen_name)
itemView.name.updateText(formatter)
adapter.requestManager.loadProfileImage(context, status).into(itemView.profileImage)
adapter.requestManager.loadProfileImage(context, status, adapter.profileImageStyle,
itemView.profileImage.cornerRadius, itemView.profileImage.cornerRadiusRatio)
.into(itemView.profileImage)
val typeIconRes = Utils.getUserTypeIconRes(status.user_is_verified, status.user_is_protected)
val typeDescriptionRes = Utils.getUserTypeDescriptionRes(status.user_is_verified, status.user_is_protected)
@ -1375,7 +1377,7 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
fun displayUser(item: ParcelableUser) {
val context = adapter.context
adapter.requestManager.loadProfileImage(context, item).into(profileImageView)
adapter.requestManager.loadProfileImage(context, item, adapter.profileImageStyle).into(profileImageView)
}
override fun onClick(v: View) {

View File

@ -525,7 +525,8 @@ class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
val width = if (bannerWidth > 0) bannerWidth else defWidth
val requestManager = Glide.with(this)
requestManager.loadProfileBanner(context, user, width).into(profileBanner)
requestManager.loadOriginalProfileImage(context, user, profileImage.style).into(profileImage)
requestManager.loadOriginalProfileImage(context, user, profileImage.style,
profileImage.cornerRadius, profileImage.cornerRadiusRatio).into(profileImage)
val relationship = relationship
if (relationship == null) {
getFriendship()

View File

@ -42,6 +42,7 @@ import com.twitter.Validator
import kotlinx.android.synthetic.main.fragment_user_profile_editor.*
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.kpreferences.get
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.ProfileUpdate
@ -50,6 +51,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
import org.mariotaku.twidere.activity.ThemedMediaPickerActivity
import org.mariotaku.twidere.constant.profileImageStyleKey
import org.mariotaku.twidere.extension.loadProfileBanner
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
@ -289,7 +291,7 @@ class UserProfileEditorFragment : BaseFragment(), OnSizeChangedListener, TextWat
editLocation.setText(user.location)
editUrl.setText(if (isEmpty(user.url_expanded)) user.url else user.url_expanded)
Glide.with(this).loadProfileImage(context, user).into(profileImage)
Glide.with(this).loadProfileImage(context, user, 0).into(profileImage)
Glide.with(this).loadProfileBanner(context, user, resources.displayMetrics.widthPixels).into(profileBanner)
Glide.with(this).load(user.profile_background_url).into(profileBackground)

View File

@ -249,8 +249,9 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
val summary = data.getSubtitle(context)
val requestManager = Glide.with(this)
requestManager.loadProfileImage(context, data).into(conversationAvatar)
requestManager.loadProfileImage(context, data, size = ProfileImageSize.REASONABLY_SMALL).into(appBarIcon)
val profileImageStyle = preferences[profileImageStyleKey]
requestManager.loadProfileImage(context, data, profileImageStyle).into(conversationAvatar)
requestManager.loadProfileImage(context, data, profileImageStyle, size = ProfileImageSize.REASONABLY_SMALL).into(appBarIcon)
appBarTitle.text = name
conversationTitle.text = name
if (summary != null) {

View File

@ -480,7 +480,8 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment<Messages
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(conversationTitle, null,
null, stateIcon, null)
Glide.with(this).loadProfileImage(context, conversation).into(conversationAvatar)
Glide.with(this).loadProfileImage(context, conversation, preferences[profileImageStyleKey])
.into(conversationAvatar)
}
internal class AddMediaTask(

View File

@ -50,7 +50,7 @@ class ConnectivityStateReceiver : BroadcastReceiver() {
val appContext = context.applicationContext
val cm = appContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val isNetworkMetered = ConnectivityManagerCompat.isActiveNetworkMetered(cm)
DependencyHolder.get(context).mediaLoader.isNetworkMetered = isNetworkMetered
DependencyHolder.get(context).mediaPreloader.isNetworkMetered = isNetworkMetered
val isCharging = Utils.isCharging(appContext)
if (!isNetworkMetered && isCharging) {
val currentTime = System.currentTimeMillis()

View File

@ -22,7 +22,7 @@ abstract class BaseAbstractTask<Params, Result, Callback>(val context: Context)
@Inject
lateinit var microBlogWrapper: AsyncTwitterWrapper
@Inject
lateinit var mediaLoader: MediaLoaderWrapper
lateinit var mediaPreloader: MediaPreloader
@Inject
lateinit var preferences: SharedPreferencesWrapper
@Inject

View File

@ -133,7 +133,7 @@ abstract class GetActivitiesTask(
val item = activities[i]
val activity = ParcelableActivityUtils.fromActivity(item, details.key, false,
profileImageSize)
mediaLoader.preloadActivity(activity)
mediaPreloader.preloadActivity(activity)
activity.position_key = GetStatusesTask.getPositionKey(activity.timestamp,
activity.timestamp, lastSortId, sortDiff, i, activities.size)
if (deleteBound[0] < 0) {

View File

@ -174,7 +174,7 @@ abstract class GetStatusesTask(
status.position_key = getPositionKey(status.timestamp, status.sort_id, lastSortId,
sortDiff, i, statuses.size)
status.inserted_date = System.currentTimeMillis()
mediaLoader.preloadStatus(status)
mediaPreloader.preloadStatus(status)
values[i] = creator.create(status)
if (minIdx == -1 || item < statuses[minIdx]) {
minIdx = i

View File

@ -19,16 +19,19 @@
package org.mariotaku.twidere.util
import android.content.Context
import android.content.SharedPreferences
import com.bumptech.glide.Glide
import org.mariotaku.kpreferences.get
import org.mariotaku.twidere.constant.mediaPreloadKey
import org.mariotaku.twidere.constant.mediaPreloadOnWifiOnlyKey
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.model.ParcelableActivity
import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.util.getActivityStatus
class MediaLoaderWrapper {
class MediaPreloader(val context: Context) {
var isNetworkMetered: Boolean = true
private var preloadEnabled: Boolean = false
@ -39,8 +42,7 @@ class MediaLoaderWrapper {
fun preloadStatus(status: ParcelableStatus) {
if (!shouldPreload) return
preloadProfileImage(status.user_profile_image_url)
preloadProfileImage(status.quoted_user_profile_image)
Glide.with(context).loadProfileImage(context, status, 0).preload()
preloadMedia(status.media)
preloadMedia(status.quoted_media)
}
@ -57,15 +59,16 @@ class MediaLoaderWrapper {
private fun preloadMedia(media: Array<ParcelableMedia>?) {
media?.forEach { item ->
val url = item.preview_url ?: item.media_url ?: return@forEach
val url = item.preview_url ?: run {
if (item.type != ParcelableMedia.Type.IMAGE) return@run null
return@run item.media_url
} ?: return@forEach
preloadPreviewImage(url)
}
}
private fun preloadProfileImage(url: String?) {
}
private fun preloadPreviewImage(url: String?) {
Glide.with(context).load(url).preload()
}
}

View File

@ -182,12 +182,12 @@ class ApplicationModule(private val application: Application) {
@Provides
@Singleton
fun mediaLoaderWrapper(preferences: SharedPreferencesWrapper): MediaLoaderWrapper {
val wrapper = MediaLoaderWrapper()
wrapper.reloadOptions(preferences)
fun mediaLoaderWrapper(preferences: SharedPreferencesWrapper): MediaPreloader {
val preloader = MediaPreloader(application)
preloader.reloadOptions(preferences)
val cm = application.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
wrapper.isNetworkMetered = ConnectivityManagerCompat.isActiveNetworkMetered(cm)
return wrapper
preloader.isNetworkMetered = ConnectivityManagerCompat.isActiveNetworkMetered(cm)
return preloader
}
@Provides

View File

@ -69,7 +69,7 @@ class DependencyHolder internal constructor(context: Context) {
lateinit var defaultFeatures: DefaultFeatures
internal set
@Inject
lateinit var mediaLoader: MediaLoaderWrapper
lateinit var mediaPreloader: MediaPreloader
internal set
@Inject
lateinit var userColorNameManager: UserColorNameManager

View File

@ -0,0 +1,72 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.util.glide
import android.content.Context
import android.graphics.*
import com.bumptech.glide.Glide
import com.bumptech.glide.load.Transformation
import com.bumptech.glide.load.engine.Resource
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapResource
class RoundedRectTransformation(
private val bitmapPool: BitmapPool,
private val radius: Float,
private val radiusPercent: Float
) : Transformation<Bitmap> {
val rectF = RectF()
constructor(context: Context, radius: Float, radiusPercent: Float) :
this(Glide.get(context).bitmapPool, radius, radiusPercent)
override fun transform(resource: Resource<Bitmap>, outWidth: Int, outHeight: Int): Resource<Bitmap> {
val source = resource.get()
val width = source.width
val height = source.height
val bitmap = bitmapPool.get(width, height, Bitmap.Config.ARGB_8888)
?: Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
val paint = Paint()
paint.isAntiAlias = true
paint.shader = BitmapShader(source, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
rectF.right = width.toFloat()
rectF.bottom = height.toFloat()
val calculatedRadius = if (radiusPercent != 0f) {
width * radiusPercent
} else {
radius
}
drawRoundRect(canvas, calculatedRadius, paint)
return BitmapResource.obtain(bitmap, bitmapPool)
}
private fun drawRoundRect(canvas: Canvas, radius: Float, paint: Paint) {
canvas.drawRoundRect(rectF, radius, radius, paint)
}
override fun getId(): String {
return "RoundedRectTransformation(radius=$radius, radiusPercent=$radius)"
}
}

View File

@ -0,0 +1,79 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view.holder
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.CompoundButton
import android.widget.ImageView
import android.widget.TextView
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.AccountDetailsAdapter
import org.mariotaku.twidere.extension.loadProfileImage
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.view.ProfileImageView
import org.mariotaku.twidere.view.iface.IColorLabelView
class AccountViewHolder(
itemView: View,
val adapter: AccountDetailsAdapter
) : RecyclerView.ViewHolder(itemView) {
private val content = itemView as IColorLabelView
private val name = itemView.findViewById(android.R.id.text1) as TextView
private val screenName = itemView.findViewById(android.R.id.text2) as TextView
private val profileImage = itemView.findViewById(android.R.id.icon) as ProfileImageView
private val toggle = itemView.findViewById(android.R.id.toggle) as CompoundButton
private val toggleContainer = itemView.findViewById(R.id.toggle_container)
private val accountType = itemView.findViewById(R.id.account_type) as ImageView
private val dragHandle = itemView.findViewById(R.id.drag_handle)
init {
profileImage.style = adapter.profileImageStyle
}
fun setAccountColor(color: Int) {
content.drawEnd(color)
}
fun setSortEnabled(enabled: Boolean) {
dragHandle.visibility = if (enabled) View.VISIBLE else View.GONE
}
fun display(details: AccountDetails) {
name.text = details.user.name
screenName.text = String.format("@%s", details.user.screen_name)
setAccountColor(details.color)
if (adapter.profileImageEnabled) {
adapter.requestManager.loadProfileImage(adapter.context, details, adapter.profileImageStyle,
profileImage.cornerRadius, profileImage.cornerRadiusRatio).into(profileImage)
} else {
// TODO: display stub image?
}
accountType.setImageResource(AccountUtils.getAccountTypeIcon(details.type))
toggle.isChecked = details.activated
toggle.setOnCheckedChangeListener(adapter.checkedChangeListener)
toggle.tag = layoutPosition
toggleContainer.visibility = if (adapter.switchEnabled) View.VISIBLE else View.GONE
setSortEnabled(adapter.sortEnabled)
}
}

View File

@ -135,7 +135,8 @@ class ActivityTitleSummaryViewHolder(
if (i < length) {
view.visibility = View.VISIBLE
val context = adapter.context
adapter.requestManager.loadProfileImage(context, users[i]).into(view)
adapter.requestManager.loadProfileImage(context, users[i], adapter.profileImageStyle)
.into(view)
} else {
view.visibility = View.GONE
}

View File

@ -32,6 +32,7 @@ import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
import org.mariotaku.twidere.view.ProfileImageView
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
class MediaStatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) : RecyclerView.ViewHolder(itemView), IStatusViewHolder, View.OnClickListener, View.OnLongClickListener {
@ -41,7 +42,7 @@ class MediaStatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView:
private val mediaImageContainer = itemView.mediaImageContainer
private val mediaImageView = itemView.mediaImage
override val profileImageView: ImageView = itemView.mediaProfileImage
override val profileImageView: ProfileImageView = itemView.mediaProfileImage
private val mediaTextView = itemView.mediaText
private var listener: IStatusViewHolder.StatusClickListener? = null
@ -80,7 +81,9 @@ class MediaStatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView:
mediaImageView.setHasPlayIcon(ParcelableMediaUtils.hasPlayIcon(firstMedia.type))
val context = itemView.context
adapter.requestManager.loadProfileImage(context, status).into(profileImageView)
adapter.requestManager.loadProfileImage(context, status,
adapter.profileImageStyle, profileImageView.cornerRadius,
profileImageView.cornerRadiusRatio).into(profileImageView)
// TODO image loaded event and credentials
adapter.requestManager.load(firstMedia.preview_url).into(mediaImageView)
}

View File

@ -34,7 +34,8 @@ open class SimpleUserViewHolder<out A : IContentAdapter>(
secondaryNameView.text = "@${user.screen_name}"
if (adapter.profileImageEnabled) {
val context = itemView.context
adapter.requestManager.loadProfileImage(context, user).into(profileImageView)
adapter.requestManager.loadProfileImage(context, user, adapter.profileImageStyle)
.into(profileImageView)
profileImageView.visibility = View.VISIBLE
} else {
profileImageView.visibility = View.GONE

View File

@ -101,7 +101,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
profileImageView.visibility = if (profileImageEnabled) View.VISIBLE else View.GONE
statusContentUpperSpace.visibility = View.VISIBLE
profileImageView.setImageResource(R.drawable.ic_profile_image_twidere)
adapter.requestManager.loadProfileImage(itemView.context, R.drawable.ic_profile_image_twidere,
adapter.profileImageStyle, profileImageView.cornerRadius,
profileImageView.cornerRadiusRatio).into(profileImageView)
nameView.name = TWIDERE_PREVIEW_NAME
nameView.screenName = "@" + TWIDERE_PREVIEW_SCREEN_NAME
nameView.updateText(adapter.bidiFormatter)
@ -297,7 +299,9 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
if (adapter.profileImageEnabled) {
profileImageView.visibility = View.VISIBLE
requestManager.loadProfileImage(context, status).into(profileImageView)
requestManager.loadProfileImage(context, status, adapter.profileImageStyle,
profileImageView.cornerRadius, profileImageView.cornerRadiusRatio)
.into(profileImageView)
profileTypeView.setImageResource(getUserTypeIconRes(status.user_is_verified, status.user_is_protected))
profileTypeView.visibility = View.VISIBLE

View File

@ -135,7 +135,8 @@ class UserViewHolder(
if (adapter.profileImageEnabled) {
profileImageView.visibility = View.VISIBLE
adapter.requestManager.loadProfileImage(context, user).into(profileImageView)
adapter.requestManager.loadProfileImage(context, user, adapter.profileImageStyle,
profileImageView.cornerRadius, profileImageView.cornerRadiusRatio).into(profileImageView)
} else {
profileImageView.visibility = View.GONE
}

View File

@ -83,7 +83,8 @@ abstract class AbsMessageViewHolder(itemView: View, val adapter: MessagesConvers
if (adapter.displaySenderProfile && adapter.profileImageEnabled && sender != null
&& !message.is_outgoing) {
this.visibility = View.VISIBLE
adapter.requestManager.loadProfileImage(context, sender).into(this)
adapter.requestManager.loadProfileImage(context, sender,
adapter.profileImageStyle).into(this)
} else {
this.visibility = View.GONE
}

View File

@ -49,7 +49,20 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
private val unreadCount by lazy { itemView.unreadCount }
init {
setup()
val textSize = adapter.textSize
name.setPrimaryTextSize(textSize * 1.05f)
name.setSecondaryTextSize(textSize * 0.95f)
text.textSize = textSize
time.textSize = textSize * 0.85f
profileImage.style = adapter.profileImageStyle
itemView.setOnClickListener {
adapter.listener?.onConversationClick(layoutPosition)
}
profileImage.setOnClickListener {
adapter.listener?.onProfileImageClick(layoutPosition)
}
}
fun display(conversation: ParcelableMessageConversation) {
@ -83,7 +96,9 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
} else {
stateIndicator.visibility = View.GONE
}
adapter.requestManager.loadProfileImage(adapter.context, conversation).into(profileImage)
adapter.requestManager.loadProfileImage(adapter.context, conversation,
adapter.profileImageStyle, profileImage.cornerRadius,
profileImage.cornerRadiusRatio).into(profileImage)
if (conversation.unread_count > 0) {
unreadCount.visibility = View.VISIBLE
unreadCount.text = conversation.unread_count.toString()
@ -92,21 +107,6 @@ class MessageEntryViewHolder(itemView: View, val adapter: MessagesEntriesAdapter
}
}
private fun setup() {
val textSize = adapter.textSize
name.setPrimaryTextSize(textSize * 1.05f)
name.setSecondaryTextSize(textSize * 0.95f)
text.textSize = textSize
time.textSize = textSize * 0.85f
itemView.setOnClickListener {
adapter.listener?.onConversationClick(layoutPosition)
}
profileImage.setOnClickListener {
adapter.listener?.onProfileImageClick(layoutPosition)
}
}
companion object {
const val layoutResource = R.layout.list_item_message_entry
}