From c52aa2da6846eaf203bda5eff429c60ca2933af3 Mon Sep 17 00:00:00 2001 From: Mariotaku Lee Date: Tue, 7 Mar 2017 17:22:02 +0800 Subject: [PATCH] improved profile image on pre-lollipop devices added sponsors in README --- README.md | 6 +- resources/logos/sujitech_logo.png | Bin 0 -> 26731 bytes .../preference/AccountsListPreference.java | 8 +- .../twidere/util/media/MediaPlayerWrapper.kt | 156 ------------------ .../twidere/view/ShapedImageView.java | 8 + .../view/holder/AccountViewHolder.java | 58 ------- .../activity/AccountSelectorActivity.kt | 4 +- .../twidere/activity/ComposeActivity.kt | 5 +- .../activity/QuickSearchBarActivity.kt | 5 +- .../twidere/adapter/AccountDetailsAdapter.kt | 48 ++---- .../twidere/adapter/AccountsSpinnerAdapter.kt | 2 +- .../adapter/ComposeAutoCompleteAdapter.kt | 3 +- .../twidere/app/TwidereApplication.kt | 4 +- .../twidere/extension/GlideExtensions.kt | 73 +++++--- .../fragment/AccountsDashboardFragment.kt | 14 +- .../fragment/AccountsManagerFragment.kt | 4 +- .../twidere/fragment/StatusFragment.kt | 6 +- .../twidere/fragment/UserFragment.kt | 3 +- .../fragment/UserProfileEditorFragment.kt | 4 +- .../MessageConversationInfoFragment.kt | 5 +- .../message/MessagesConversationFragment.kt | 3 +- .../receiver/ConnectivityStateReceiver.kt | 2 +- .../twidere/task/BaseAbstractTask.kt | 2 +- .../twidere/task/twitter/GetActivitiesTask.kt | 2 +- .../twidere/task/twitter/GetStatusesTask.kt | 2 +- ...ediaLoaderWrapper.kt => MediaPreloader.kt} | 17 +- .../util/api/TwitterAndroidExtraHeaders.kt | 0 .../twidere/util/api/UserAgentExtraHeaders.kt | 0 .../twidere/util/dagger/ApplicationModule.kt | 10 +- .../twidere/util/dagger/DependencyHolder.kt | 2 +- .../util/glide/RoundedRectTransformation.kt | 72 ++++++++ .../twidere/view/holder/AccountViewHolder.kt | 79 +++++++++ .../holder/ActivityTitleSummaryViewHolder.kt | 3 +- .../view/holder/MediaStatusViewHolder.kt | 7 +- .../view/holder/SimpleUserViewHolder.kt | 3 +- .../twidere/view/holder/StatusViewHolder.kt | 8 +- .../twidere/view/holder/UserViewHolder.kt | 3 +- .../holder/message/AbsMessageViewHolder.kt | 3 +- .../holder/message/MessageEntryViewHolder.kt | 34 ++-- 39 files changed, 324 insertions(+), 344 deletions(-) create mode 100644 resources/logos/sujitech_logo.png delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/util/media/MediaPlayerWrapper.kt delete mode 100644 twidere/src/main/java/org/mariotaku/twidere/view/holder/AccountViewHolder.java rename twidere/src/main/kotlin/org/mariotaku/twidere/util/{MediaLoaderWrapper.kt => MediaPreloader.kt} (81%) rename twidere/src/main/{java => kotlin}/org/mariotaku/twidere/util/api/TwitterAndroidExtraHeaders.kt (100%) rename twidere/src/main/{java => kotlin}/org/mariotaku/twidere/util/api/UserAgentExtraHeaders.kt (100%) create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/util/glide/RoundedRectTransformation.kt create mode 100644 twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/AccountViewHolder.kt diff --git a/README.md b/README.md index 62aa1cd3d..b71b64040 100644 --- a/README.md +++ b/README.md @@ -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) + --- diff --git a/resources/logos/sujitech_logo.png b/resources/logos/sujitech_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..07f0887559c080dcf7f5beb201b840cde2a1276a GIT binary patch literal 26731 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 PJVR1URy0Rg=jHzbF{$Wu literal 0 HcmV?d00001 diff --git a/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java b/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java index 17e52ec11..db7e9e481 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java +++ b/twidere/src/main/java/org/mariotaku/twidere/preference/AccountsListPreference.java @@ -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); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaPlayerWrapper.kt b/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaPlayerWrapper.kt deleted file mode 100644 index 26cf07371..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/media/MediaPlayerWrapper.kt +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2017 Mariotaku Lee - * - * 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 . - */ - -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) - - } - -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java b/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java index 51117e3c3..8869d2e1d 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java +++ b/twidere/src/main/java/org/mariotaku/twidere/view/ShapedImageView.java @@ -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; } diff --git a/twidere/src/main/java/org/mariotaku/twidere/view/holder/AccountViewHolder.java b/twidere/src/main/java/org/mariotaku/twidere/view/holder/AccountViewHolder.java deleted file mode 100644 index 3b9183acd..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/view/holder/AccountViewHolder.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Twidere - Twitter client for Android - * - * Copyright (C) 2012-2014 Mariotaku Lee - * - * 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 . - */ - -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); - } -} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/AccountSelectorActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/AccountSelectorActivity.kt index 75fb1992e..767f2769c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/AccountSelectorActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/AccountSelectorActivity.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index 1ca7a4153..e45d23953 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/QuickSearchBarActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/QuickSearchBarActivity.kt index 2640d1a07..b7dc33e68 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/QuickSearchBarActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/QuickSearchBarActivity.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountDetailsAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountDetailsAdapter.kt index dcb78834b..fa9b9270b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountDetailsAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountDetailsAdapter.kt @@ -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(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) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt index 0e94f8aa4..020add9d4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/AccountsSpinnerAdapter.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt index d23193976..b20b67268 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ComposeAutoCompleteAdapter.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt index a3166f99f..bc07d88d5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/app/TwidereApplication.kt @@ -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() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/GlideExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/GlideExtensions.kt index 26413fbad..cd0c30b59 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/GlideExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/GlideExtensions.kt @@ -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 { - 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 { - return configureLoadProfileImage(context, shapeStyle) { load(resourceId) } + @ImageShapeStyle shapeStyle: Int, + cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder { + 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 { - 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 { 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 { - return configureLoadProfileImage(context, shapeStyle) { load(userList.user_profile_image_url) } + @ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE, + cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder { + 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 { - return configureLoadProfileImage(context, shapeStyle) { load(group.homepage_logo) } + @ImageShapeStyle shapeStyle: Int = ImageShapeStyle.SHAPE_CIRCLE, + cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder { + 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 { 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 { + @ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f +): DrawableRequestBuilder { 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 { return load(user.getBestProfileBanner(width)) } -internal inline fun configureLoadProfileImage(context: Context, shapeStyle: Int, - create: () -> DrawableTypeRequest): DrawableRequestBuilder { +internal inline fun configureLoadProfileImage(context: Context, @ImageShapeStyle shapeStyle: Int, + cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, create: () -> DrawableTypeRequest +): DrawableRequestBuilder { val builder = create() builder.diskCacheStrategy(DiskCacheStrategy.RESULT) builder.dontAnimate() @@ -134,6 +155,8 @@ internal inline fun configureLoadProfileImage(context: Context, shapeStyle: builder.bitmapTransform(CropCircleTransformation(context)) } ImageShapeStyle.SHAPE_RECTANGLE -> { + builder.bitmapTransform(RoundedRectTransformation(context, cornerRadius, + cornerRadiusRatio)) } } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt index 5a934e2e7..47ec06e1a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsDashboardFragment.kt @@ -451,7 +451,9 @@ class AccountsDashboardFragment : BaseFragment(), LoaderCallbacks, //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, 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, 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, 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) } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt index 788d59bbb..c6d7d5a58 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/AccountsManagerFragment.kt @@ -61,8 +61,8 @@ class AccountsManagerFragment : BaseFragment(), LoaderManager.LoaderCallbacks
  • val item = getItem(pos) item.activated = checked diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/StatusFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/StatusFragment.kt index a278c7c5b..f81005683 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/StatusFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/StatusFragment.kt @@ -929,7 +929,9 @@ class StatusFragment : BaseFragment(), LoaderCallbacks 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() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserProfileEditorFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserProfileEditorFragment.kt index 05f0d3f3a..da4cbacd3 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserProfileEditorFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserProfileEditorFragment.kt @@ -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) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt index 9487fe689..e734f5cd4 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessageConversationInfoFragment.kt @@ -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) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesConversationFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesConversationFragment.kt index 03e6b9597..2799320b5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesConversationFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/message/MessagesConversationFragment.kt @@ -480,7 +480,8 @@ class MessagesConversationFragment : AbsContentListRecyclerViewFragment(val context: Context) @Inject lateinit var microBlogWrapper: AsyncTwitterWrapper @Inject - lateinit var mediaLoader: MediaLoaderWrapper + lateinit var mediaPreloader: MediaPreloader @Inject lateinit var preferences: SharedPreferencesWrapper @Inject diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt index b8dfd4ccd..ea914fabb 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetActivitiesTask.kt @@ -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) { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt index cf47aff7a..95ffed504 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/GetStatusesTask.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaPreloader.kt similarity index 81% rename from twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaPreloader.kt index ed6b2e761..4787a0062 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaLoaderWrapper.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/MediaPreloader.kt @@ -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?) { 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() } } diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/api/TwitterAndroidExtraHeaders.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/api/TwitterAndroidExtraHeaders.kt similarity index 100% rename from twidere/src/main/java/org/mariotaku/twidere/util/api/TwitterAndroidExtraHeaders.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/util/api/TwitterAndroidExtraHeaders.kt diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/api/UserAgentExtraHeaders.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/api/UserAgentExtraHeaders.kt similarity index 100% rename from twidere/src/main/java/org/mariotaku/twidere/util/api/UserAgentExtraHeaders.kt rename to twidere/src/main/kotlin/org/mariotaku/twidere/util/api/UserAgentExtraHeaders.kt diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt index afe0d2c82..93e4d293f 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/ApplicationModule.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt index 919e2345f..e395376b1 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/glide/RoundedRectTransformation.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/glide/RoundedRectTransformation.kt new file mode 100644 index 000000000..16225e6b9 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/glide/RoundedRectTransformation.kt @@ -0,0 +1,72 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +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 { + val rectF = RectF() + + constructor(context: Context, radius: Float, radiusPercent: Float) : + this(Glide.get(context).bitmapPool, radius, radiusPercent) + + override fun transform(resource: Resource, outWidth: Int, outHeight: Int): Resource { + 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)" + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/AccountViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/AccountViewHolder.kt new file mode 100644 index 000000000..f74b8e782 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/AccountViewHolder.kt @@ -0,0 +1,79 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2014 Mariotaku Lee + * + * 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 . + */ + +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) + } +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt index f119a233f..49ea4dc1e 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/ActivityTitleSummaryViewHolder.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MediaStatusViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MediaStatusViewHolder.kt index d34cbe9ca..a77457da5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MediaStatusViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/MediaStatusViewHolder.kt @@ -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) } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/SimpleUserViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/SimpleUserViewHolder.kt index 55c9669e1..9a6fefc0c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/SimpleUserViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/SimpleUserViewHolder.kt @@ -34,7 +34,8 @@ open class SimpleUserViewHolder( 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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt index 227c62cfa..f510279de 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/StatusViewHolder.kt @@ -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 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt index ecc9dbe8e..c33feb410 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/UserViewHolder.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/AbsMessageViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/AbsMessageViewHolder.kt index 4a22e27c8..b5d1ade83 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/AbsMessageViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/AbsMessageViewHolder.kt @@ -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 } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageEntryViewHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageEntryViewHolder.kt index 9c88a72d8..c012d8700 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageEntryViewHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/view/holder/message/MessageEntryViewHolder.kt @@ -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 }