improved profile image on pre-lollipop devices
added sponsors in README
This commit is contained in:
parent
d7e107c126
commit
c52aa2da68
|
@ -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 |
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)"
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue