Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/fragment/UserFragment.kt

1670 lines
72 KiB
Kotlin
Raw Normal View History

2016-06-29 15:47:52 +02:00
/*
* 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.fragment
2016-12-04 06:45:57 +01:00
import android.accounts.AccountManager
2016-06-29 15:47:52 +02:00
import android.animation.ArgbEvaluator
import android.annotation.TargetApi
import android.app.Activity
2016-08-30 14:23:59 +02:00
import android.app.Dialog
2016-06-29 15:47:52 +02:00
import android.content.Context
2016-08-30 14:23:59 +02:00
import android.content.DialogInterface
2016-06-29 15:47:52 +02:00
import android.content.Intent
import android.graphics.Color
import android.graphics.Outline
import android.graphics.Rect
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.net.Uri
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.support.annotation.UiThread
2016-08-30 14:23:59 +02:00
import android.support.v4.app.DialogFragment
2016-06-29 15:47:52 +02:00
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.AsyncTaskLoader
import android.support.v4.content.Loader
import android.support.v4.content.res.ResourcesCompat
import android.support.v4.view.ViewCompat
import android.support.v4.view.ViewPager.OnPageChangeListener
import android.support.v4.view.WindowCompat
2016-08-30 14:23:59 +02:00
import android.support.v7.app.AlertDialog
2016-06-29 15:47:52 +02:00
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.text.SpannableStringBuilder
import android.text.TextUtils
import android.text.util.Linkify
2016-08-30 14:23:59 +02:00
import android.util.SparseBooleanArray
2016-06-29 15:47:52 +02:00
import android.view.*
import android.view.View.OnClickListener
import android.view.View.OnTouchListener
import android.view.animation.AnimationUtils
import com.afollestad.appthemeengine.ATEActivity
import com.afollestad.appthemeengine.Config
import com.squareup.otto.Subscribe
import edu.tsinghua.hotmobi.HotMobiLogger
import edu.tsinghua.hotmobi.model.UserEvent
import kotlinx.android.synthetic.main.fragment_user.*
import kotlinx.android.synthetic.main.fragment_user.view.*
import kotlinx.android.synthetic.main.header_user.*
import kotlinx.android.synthetic.main.header_user.view.*
import kotlinx.android.synthetic.main.layout_content_fragment_common.*
import kotlinx.android.synthetic.main.layout_content_pages_common.*
import nl.komponents.kovenant.task
2016-08-30 14:23:59 +02:00
import nl.komponents.kovenant.then
import nl.komponents.kovenant.ui.alwaysUi
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.promiseOnUi
import nl.komponents.kovenant.ui.successUi
2016-06-29 15:47:52 +02:00
import org.apache.commons.lang3.ObjectUtils
2016-08-30 14:23:59 +02:00
import org.mariotaku.ktextension.Bundle
2016-06-29 15:47:52 +02:00
import org.mariotaku.ktextension.empty
2016-08-30 14:23:59 +02:00
import org.mariotaku.ktextension.set
import org.mariotaku.ktextension.toTypedArray
2016-06-29 15:47:52 +02:00
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
import org.mariotaku.microblog.library.twitter.model.Paging
2016-06-29 15:47:52 +02:00
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
2016-08-30 14:23:59 +02:00
import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
import org.mariotaku.twidere.activity.LinkHandlerActivity
import org.mariotaku.twidere.activity.iface.IExtendedActivity
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.adapter.SupportTabsAdapter
2016-12-03 06:48:40 +01:00
import org.mariotaku.twidere.annotation.AccountType
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
2016-08-19 16:25:27 +02:00
import org.mariotaku.twidere.fragment.AbsStatusesFragment.StatusesFragmentDelegate
import org.mariotaku.twidere.fragment.UserTimelineFragment.UserTimelineFragmentDelegate
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowsInsetsCallback
import org.mariotaku.twidere.fragment.iface.IToolBarSupportFragment
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
import org.mariotaku.twidere.graphic.ActionBarColorDrawable
import org.mariotaku.twidere.graphic.ActionIconDrawable
import org.mariotaku.twidere.loader.ParcelableUserLoader
import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.message.FriendshipTaskEvent
import org.mariotaku.twidere.model.message.FriendshipUpdatedEvent
import org.mariotaku.twidere.model.message.ProfileUpdatedEvent
import org.mariotaku.twidere.model.message.TaskStateChangedEvent
2016-11-30 08:18:43 +01:00
import org.mariotaku.twidere.model.tab.DrawableHolder
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.model.util.*
import org.mariotaku.twidere.provider.TwidereDataStore.*
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.util.TwidereLinkify.OnLinkClickListener
import org.mariotaku.twidere.util.UserColorNameManager.UserColorChangedListener
import org.mariotaku.twidere.util.UserColorNameManager.UserNicknameChangedListener
import org.mariotaku.twidere.util.menu.TwidereMenuInfo
import org.mariotaku.twidere.util.support.ActivitySupport
import org.mariotaku.twidere.util.support.ActivitySupport.TaskDescriptionCompat
import org.mariotaku.twidere.util.support.ViewSupport
import org.mariotaku.twidere.util.support.WindowSupport
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback
import org.mariotaku.twidere.view.TabPagerIndicator
import org.mariotaku.twidere.view.iface.IExtendedView.OnSizeChangedListener
import java.util.*
2016-08-19 16:25:27 +02:00
class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener,
OnSizeChangedListener, OnTouchListener, DrawerCallback, SupportFragmentCallback,
SystemWindowsInsetsCallback, RefreshScrollTopInterface, OnPageChangeListener,
KeyboardShortcutCallback, UserColorChangedListener, UserNicknameChangedListener,
IToolBarSupportFragment, StatusesFragmentDelegate, UserTimelineFragmentDelegate {
2016-06-29 15:47:52 +02:00
override val toolbar: Toolbar
get() = profileContentContainer.toolbar
2016-12-11 07:29:00 +01:00
private var actionBarBackground: ActionBarDrawable? = null
private lateinit var pagerAdapter: SupportTabsAdapter
2016-06-29 15:47:52 +02:00
// Data fields
var user: ParcelableUser? = null
private set
2016-12-04 04:58:03 +01:00
private var account: AccountDetails? = null
2016-11-26 10:41:35 +01:00
private var relationship: ParcelableRelationship? = null
2016-08-20 04:30:54 +02:00
private var locale: Locale? = null
2016-12-11 07:29:00 +01:00
private var getUserInfoLoaderInitialized: Boolean = false
private var getFriendShipLoaderInitialized: Boolean = false
private var bannerWidth: Int = 0
2016-08-20 04:30:54 +02:00
private var cardBackgroundColor: Int = 0
private var actionBarShadowColor: Int = 0
private var uiColor: Int = 0
2016-12-11 07:29:00 +01:00
private var primaryColor: Int = 0
private var primaryColorDark: Int = 0
2016-08-20 04:30:54 +02:00
private var nameFirst: Boolean = false
2016-12-11 07:29:00 +01:00
private var previousTabItemIsDark: Int = 0
private var previousActionBarItemIsDark: Int = 0
private var hideBirthdayView: Boolean = false
2016-08-20 04:30:54 +02:00
private var userEvent: UserEvent? = null
2016-06-29 15:47:52 +02:00
2016-11-26 10:41:35 +01:00
private val friendshipLoaderCallbacks = object : LoaderCallbacks<SingleResponse<ParcelableRelationship>> {
2016-06-29 15:47:52 +02:00
2016-11-26 10:41:35 +01:00
override fun onCreateLoader(id: Int, args: Bundle): Loader<SingleResponse<ParcelableRelationship>> {
2016-11-30 08:18:43 +01:00
activity.invalidateOptionsMenu()
2016-06-29 15:47:52 +02:00
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val user = args.getParcelable<ParcelableUser>(EXTRA_USER)
if (user != null && user.key == accountKey) {
followingYouIndicator.visibility = View.GONE
followContainer.follow.visibility = View.VISIBLE
2016-12-11 07:29:00 +01:00
followProgress.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
} else {
followingYouIndicator.visibility = View.GONE
followContainer.follow.visibility = View.GONE
2016-12-11 07:29:00 +01:00
followProgress.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
}
return UserRelationshipLoader(activity, accountKey, user)
}
2016-11-26 10:41:35 +01:00
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableRelationship>>) {
2016-06-29 15:47:52 +02:00
}
2016-11-26 10:41:35 +01:00
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableRelationship>>,
data: SingleResponse<ParcelableRelationship>) {
2016-12-11 07:29:00 +01:00
followProgress.visibility = View.GONE
2016-06-29 15:47:52 +02:00
val relationship = data.data
displayRelationship(user, relationship)
updateOptionsMenuVisibility()
}
}
private val userInfoLoaderCallbacks = object : LoaderCallbacks<SingleResponse<ParcelableUser>> {
2016-06-29 15:47:52 +02:00
override fun onCreateLoader(id: Int, args: Bundle): Loader<SingleResponse<ParcelableUser>> {
val omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
val accountKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val userId = args.getParcelable<UserKey>(EXTRA_USER_KEY)
val screenName = args.getString(EXTRA_SCREEN_NAME)
if (user == null && (!omitIntentExtra || !args.containsKey(EXTRA_USER))) {
2016-08-19 16:25:27 +02:00
cardContent.visibility = View.GONE
errorContainer.visibility = View.GONE
progressContainer.visibility = View.VISIBLE
errorText.text = null
errorText.visibility = View.GONE
2016-06-29 15:47:52 +02:00
}
val user = this@UserFragment.user
val loadFromCache = user == null || !user.is_cache && user.key.maybeEquals(userId)
return ParcelableUserLoader(activity, accountKey, userId, screenName, arguments,
omitIntentExtra, loadFromCache)
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableUser>>) {
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUser>>,
data: SingleResponse<ParcelableUser>) {
val activity = activity ?: return
2016-07-05 15:19:51 +02:00
if (data.data != null) {
2016-06-29 15:47:52 +02:00
val user = data.data
2016-08-19 16:25:27 +02:00
cardContent.visibility = View.VISIBLE
errorContainer.visibility = View.GONE
progressContainer.visibility = View.GONE
2016-12-04 04:58:03 +01:00
val account: AccountDetails = data.extras.getParcelable(EXTRA_ACCOUNT)
2016-06-29 15:47:52 +02:00
displayUser(user, account)
if (user.is_cache) {
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, user.account_key)
args.putParcelable(EXTRA_USER_KEY, user.key)
args.putString(EXTRA_SCREEN_NAME, user.screen_name)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
loaderManager.restartLoader(LOADER_ID_USER, args, this)
}
updateOptionsMenuVisibility()
} else if (user != null && user!!.is_cache) {
2016-08-19 16:25:27 +02:00
cardContent.visibility = View.VISIBLE
errorContainer.visibility = View.GONE
progressContainer.visibility = View.GONE
displayUser(user, account)
2016-06-29 15:47:52 +02:00
updateOptionsMenuVisibility()
} else {
if (data.hasException()) {
2016-08-19 16:25:27 +02:00
errorText.text = Utils.getErrorMessage(activity, data.exception)
errorText.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
}
2016-08-19 16:25:27 +02:00
cardContent.visibility = View.GONE
errorContainer.visibility = View.VISIBLE
progressContainer.visibility = View.GONE
2016-06-29 15:47:52 +02:00
displayUser(null, null)
updateOptionsMenuVisibility()
}
}
}
2016-08-19 16:25:27 +02:00
override val pinnedStatusIds: Array<String>?
get() = user?.extras?.pinned_status_ids
2016-06-29 15:47:52 +02:00
private fun updateOptionsMenuVisibility() {
2016-08-20 04:30:54 +02:00
setHasOptionsMenu(user != null && relationship != null)
2016-06-29 15:47:52 +02:00
}
private fun displayRelationship(user: ParcelableUser?,
2016-11-26 10:41:35 +01:00
userRelationship: ParcelableRelationship?) {
2016-06-29 15:47:52 +02:00
if (user == null) {
2016-08-20 04:30:54 +02:00
relationship = null
2016-06-29 15:47:52 +02:00
return
}
if (user.account_key.maybeEquals(user.key)) {
followContainer.follow.setText(R.string.edit)
followContainer.follow.visibility = View.VISIBLE
2016-08-20 04:30:54 +02:00
relationship = userRelationship
2016-06-29 15:47:52 +02:00
return
}
if (userRelationship == null || !userRelationship.check(user)) {
2016-08-20 04:30:54 +02:00
relationship = null
2016-06-29 15:47:52 +02:00
return
} else {
2016-08-20 04:30:54 +02:00
relationship = userRelationship
2016-06-29 15:47:52 +02:00
}
2016-11-30 08:18:43 +01:00
activity.invalidateOptionsMenu()
2016-06-29 15:47:52 +02:00
followContainer.follow.isEnabled = userRelationship.blocking || !userRelationship.blocked_by
if (userRelationship.blocked_by) {
2016-12-11 07:29:00 +01:00
pagesErrorContainer.visibility = View.GONE
pagesErrorText.text = null
pagesContent.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
} else if (!userRelationship.following && user.is_protected) {
2016-12-11 07:29:00 +01:00
pagesErrorContainer.visibility = View.VISIBLE
pagesErrorText.setText(R.string.user_protected_summary)
pagesErrorIcon.setImageResource(R.drawable.ic_info_locked)
pagesContent.visibility = View.GONE
2016-06-29 15:47:52 +02:00
} else {
2016-12-11 07:29:00 +01:00
pagesErrorContainer.visibility = View.GONE
pagesErrorText.text = null
pagesContent.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
}
if (userRelationship.blocking) {
followContainer.follow.setText(R.string.unblock)
} else if (userRelationship.following) {
followContainer.follow.setText(R.string.unfollow)
} else if (user.is_follow_request_sent) {
followContainer.follow.setText(R.string.requested)
} else {
followContainer.follow.setText(R.string.follow)
}
followContainer.follow.compoundDrawablePadding = Math.round(followContainer.follow.textSize * 0.25f)
followingYouIndicator.visibility = if (userRelationship.followed_by) View.VISIBLE else View.GONE
2016-12-13 01:23:41 +01:00
val resolver = context.contentResolver
task {
resolver.insert(CachedUsers.CONTENT_URI, ParcelableUserValuesCreator.create(user))
2016-11-26 10:41:35 +01:00
resolver.insert(CachedRelationships.CONTENT_URI, ParcelableRelationshipValuesCreator.create(userRelationship))
}
2016-06-29 15:47:52 +02:00
followContainer.follow.visibility = View.VISIBLE
}
override fun canScroll(dy: Float): Boolean {
val fragment = currentVisibleFragment
return fragment is DrawerCallback && fragment.canScroll(dy)
}
override fun cancelTouch() {
val fragment = currentVisibleFragment
if (fragment is DrawerCallback) {
fragment.cancelTouch()
}
}
override fun fling(velocity: Float) {
val fragment = currentVisibleFragment
if (fragment is DrawerCallback) {
fragment.fling(velocity)
}
}
override fun isScrollContent(x: Float, y: Float): Boolean {
val v = viewPager
val location = IntArray(2)
2016-12-11 07:29:00 +01:00
v.getLocationInWindow(location)
2016-06-29 15:47:52 +02:00
return x >= location[0] && x <= location[0] + v.width
&& y >= location[1] && y <= location[1] + v.height
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
updateSubtitle()
}
private fun updateSubtitle() {
2016-08-25 04:10:53 +02:00
val activity = activity as AppCompatActivity
2016-06-29 15:47:52 +02:00
val actionBar = activity.supportActionBar ?: return
val user = this.user
if (user == null) {
actionBar.subtitle = null
return
}
2016-12-11 07:29:00 +01:00
val spec = pagerAdapter.getTab(viewPager.currentItem)
2016-06-29 15:47:52 +02:00
assert(spec.type != null)
when (spec.type) {
TAB_TYPE_STATUSES -> {
actionBar.subtitle = resources.getQuantityString(R.plurals.N_statuses,
user.statuses_count.toInt(), user.statuses_count)
}
TAB_TYPE_MEDIA -> {
if (user.media_count < 0) {
actionBar.setSubtitle(R.string.recent_media)
} else {
actionBar.subtitle = resources.getQuantityString(R.plurals.N_media,
user.media_count.toInt(), user.media_count)
}
}
TAB_TYPE_FAVORITES -> {
if (preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK)) {
actionBar.subtitle = resources.getQuantityString(R.plurals.N_favorites,
user.favorites_count.toInt(), user.favorites_count)
} else {
actionBar.subtitle = resources.getQuantityString(R.plurals.N_likes,
user.favorites_count.toInt(), user.favorites_count)
}
}
else -> {
actionBar.subtitle = null
}
}
updateTitleAlpha()
}
override fun onPageScrollStateChanged(state: Int) {
}
override fun scrollBy(dy: Float) {
val fragment = currentVisibleFragment
if (fragment is DrawerCallback) {
fragment.scrollBy(dy)
}
}
override fun shouldLayoutHeaderBottom(): Boolean {
val drawer = userProfileDrawer
val card = profileDetailsContainer
if (drawer == null || card == null) return false
return card.top + drawer.headerTop - drawer.paddingTop <= 0
}
override fun topChanged(top: Int) {
val drawer = userProfileDrawer ?: return
val offset = drawer.paddingTop - top
updateScrollOffset(offset)
val fragment = currentVisibleFragment
if (fragment is DrawerCallback) {
fragment.topChanged(top)
}
}
@UiThread
2016-12-04 04:58:03 +01:00
fun displayUser(user: ParcelableUser?, account: AccountDetails?) {
2016-06-29 15:47:52 +02:00
val activity = activity ?: return
this.user = user
this.account = account
2016-06-29 15:47:52 +02:00
if (user == null || user.key == null) {
2016-07-02 06:05:23 +02:00
profileImage.visibility = View.GONE
2016-12-11 07:29:00 +01:00
profileType.visibility = View.GONE
2016-06-29 15:47:52 +02:00
if (activity is ATEActivity) {
setUiColor(Config.primaryColor(activity, activity.ateKey))
}
return
}
2016-12-11 07:29:00 +01:00
val adapter = pagerAdapter
2016-08-19 16:25:27 +02:00
for (i in 0 until adapter.count) {
val sf = adapter.instantiateItem(viewPager, i) as? AbsStatusesFragment
sf?.initLoaderIfNeeded()
}
2016-07-02 06:05:23 +02:00
profileImage.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
val resources = resources
val lm = loaderManager
lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP)
2016-12-11 07:29:00 +01:00
cardContent.visibility = View.VISIBLE
errorContainer.visibility = View.GONE
2016-06-29 15:47:52 +02:00
progressContainer.visibility = View.GONE
this.user = user
profileImage.setBorderColor(if (user.color != 0) user.color else Color.WHITE)
profileNameContainer.drawEnd(user.account_color)
profileNameContainer.name.text = bidiFormatter.unicodeWrap(if (TextUtils.isEmpty(user.nickname)) user.name else getString(R.string.name_with_nickname, user.name, user.nickname))
val typeIconRes = Utils.getUserTypeIconRes(user.is_verified, user.is_protected)
if (typeIconRes != 0) {
profileType.setImageResource(typeIconRes)
profileType.visibility = View.VISIBLE
} else {
profileType.setImageDrawable(null)
profileType.visibility = View.GONE
}
profileNameContainer.screenName.text = "@${user.screen_name}"
val linkify = TwidereLinkify(this)
if (user.description_unescaped != null) {
val text = SpannableStringBuilder.valueOf(user.description_unescaped)
ParcelableStatusUtils.applySpans(text, user.description_spans)
linkify.applyAllLinks(text, user.account_key, false, false)
descriptionContainer.description.text = text
} else {
descriptionContainer.description.text = user.description_plain
Linkify.addLinks(descriptionContainer.description, Linkify.WEB_URLS)
}
descriptionContainer.visibility = if (descriptionContainer.description.empty) View.GONE else View.VISIBLE
locationContainer.visibility = if (TextUtils.isEmpty(user.location)) View.GONE else View.VISIBLE
locationContainer.location.text = user.location
urlContainer.visibility = if (TextUtils.isEmpty(user.url) && TextUtils.isEmpty(user.url_expanded)) View.GONE else View.VISIBLE
urlContainer.url.text = if (TextUtils.isEmpty(user.url_expanded)) user.url else user.url_expanded
val createdAt = Utils.formatToLongTimeString(activity, user.created_at)
val daysSinceCreation = (System.currentTimeMillis() - user.created_at) / 1000 / 60 / 60 / 24.toFloat()
val dailyTweets = Math.round(user.statuses_count / Math.max(1f, daysSinceCreation))
createdAtContainer.createdAt.text = resources.getQuantityString(R.plurals.created_at_with_N_tweets_per_day, dailyTweets,
createdAt, dailyTweets)
2016-08-20 04:30:54 +02:00
listedContainer.listedCount.text = Utils.getLocalizedNumber(locale, user.listed_count)
2016-06-29 15:47:52 +02:00
val groupsCount = if (user.extras != null) user.extras.groups_count else -1
2016-08-20 04:30:54 +02:00
groupsContainer.groupsCount.text = Utils.getLocalizedNumber(locale, groupsCount)
2016-12-11 07:29:00 +01:00
followersContainer.followersCount.text = Utils.getLocalizedNumber(locale, user.followers_count)
friendsContainer.friendsCount.text = Utils.getLocalizedNumber(locale, user.friends_count)
2016-06-29 15:47:52 +02:00
2016-07-02 06:05:23 +02:00
listedContainer.visibility = if (user.listed_count < 0) View.GONE else View.VISIBLE
groupsContainer.visibility = if (groupsCount < 0) View.GONE else View.VISIBLE
2016-06-29 15:47:52 +02:00
mediaLoader.displayOriginalProfileImage(profileImage, user)
if (user.color != 0) {
setUiColor(user.color)
} else if (user.link_color != 0) {
setUiColor(user.link_color)
} else if (activity is ATEActivity) {
setUiColor(Config.primaryColor(activity, activity.ateKey))
}
val defWidth = resources.displayMetrics.widthPixels
2016-12-11 07:29:00 +01:00
val width = if (bannerWidth > 0) bannerWidth else defWidth
2016-06-29 15:47:52 +02:00
val bannerUrl = ParcelableUserUtils.getProfileBannerUrl(user)
2016-07-02 06:05:23 +02:00
if (ObjectUtils.notEqual(profileBanner.tag, bannerUrl) || profileBanner.drawable == null) {
profileBanner.tag = bannerUrl
2016-06-29 15:47:52 +02:00
mediaLoader.displayProfileBanner(profileBanner, bannerUrl, width)
}
2016-08-20 04:30:54 +02:00
val relationship = relationship
2016-06-29 15:47:52 +02:00
if (relationship == null) {
getFriendship()
}
activity.title = UserColorNameManager.decideDisplayName(user.nickname, user.name,
2016-08-20 04:30:54 +02:00
user.screen_name, nameFirst)
2016-06-29 15:47:52 +02:00
val cal = Calendar.getInstance()
val currentMonth = cal.get(Calendar.MONTH)
val currentDay = cal.get(Calendar.DAY_OF_MONTH)
cal.timeInMillis = user.created_at
2016-12-11 07:29:00 +01:00
if (cal.get(Calendar.MONTH) == currentMonth && cal.get(Calendar.DAY_OF_MONTH) == currentDay && !hideBirthdayView) {
2016-07-02 06:05:23 +02:00
profileBirthdayBanner.visibility = View.VISIBLE
2016-06-29 15:47:52 +02:00
} else {
2016-07-02 06:05:23 +02:00
profileBirthdayBanner.visibility = View.GONE
2016-06-29 15:47:52 +02:00
}
updateTitleAlpha()
2016-11-30 08:18:43 +01:00
activity.invalidateOptionsMenu()
2016-06-29 15:47:52 +02:00
updateSubtitle()
}
2016-07-06 15:21:34 +02:00
override val currentVisibleFragment: Fragment?
get() {
val currentItem = viewPager.currentItem
2016-12-11 07:29:00 +01:00
if (currentItem < 0 || currentItem >= pagerAdapter.count) return null
return pagerAdapter.instantiateItem(viewPager, currentItem) as Fragment
2016-07-06 15:21:34 +02:00
}
2016-06-29 15:47:52 +02:00
override fun triggerRefresh(position: Int): Boolean {
return false
}
override fun getSystemWindowsInsets(insets: Rect): Boolean {
return false
}
2016-07-14 14:00:27 +02:00
fun getUserInfo(accountKey: UserKey, userKey: UserKey?, screenName: String?,
2016-06-29 15:47:52 +02:00
omitIntentExtra: Boolean) {
val lm = loaderManager
lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP)
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, accountKey)
args.putParcelable(EXTRA_USER_KEY, userKey)
args.putString(EXTRA_SCREEN_NAME, screenName)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
2016-12-11 07:29:00 +01:00
if (!getUserInfoLoaderInitialized) {
lm.initLoader(LOADER_ID_USER, args, userInfoLoaderCallbacks)
2016-12-11 07:29:00 +01:00
getUserInfoLoaderInitialized = true
2016-06-29 15:47:52 +02:00
} else {
lm.restartLoader(LOADER_ID_USER, args, userInfoLoaderCallbacks)
2016-06-29 15:47:52 +02:00
}
2016-08-09 09:48:16 +02:00
if (userKey == null && screenName == null) {
2016-12-11 07:29:00 +01:00
cardContent.visibility = View.GONE
errorContainer.visibility = View.GONE
2016-06-29 15:47:52 +02:00
}
}
@Subscribe
fun notifyFriendshipUpdated(event: FriendshipUpdatedEvent) {
val user = user
if (user == null || !event.isAccount(user.account_key) || !event.isUser(user.key.id))
return
getFriendship()
}
@Subscribe
fun notifyFriendshipUserUpdated(event: FriendshipTaskEvent) {
val user = user
if (user == null || !event.isSucceeded || !event.isUser(user)) return
getFriendship()
}
@Subscribe
fun notifyProfileUpdated(event: ProfileUpdatedEvent) {
val user = user
// TODO check account status
if (user == null || user != event.user) return
displayUser(event.user, account)
2016-06-29 15:47:52 +02:00
}
@Subscribe
fun notifyTaskStateChanged(event: TaskStateChangedEvent) {
2016-11-30 08:18:43 +01:00
activity.invalidateOptionsMenu()
2016-06-29 15:47:52 +02:00
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val user = user
when (requestCode) {
REQUEST_SET_COLOR -> {
if (user == null) return
if (resultCode == Activity.RESULT_OK) {
if (data == null) return
val color = data.getIntExtra(EXTRA_COLOR, Color.TRANSPARENT)
userColorNameManager.setUserColor(this.user!!.key, color)
} else if (resultCode == ColorPickerDialogActivity.RESULT_CLEARED) {
userColorNameManager.clearUserColor(this.user!!.key)
}
}
REQUEST_ADD_TO_LIST -> {
if (user == null) return
if (resultCode == Activity.RESULT_OK && data != null) {
val twitter = twitterWrapper
2016-08-20 04:30:54 +02:00
val list = data.getParcelableExtra<ParcelableUserList>(EXTRA_USER_LIST) ?: return
2016-06-29 15:47:52 +02:00
twitter.addUserListMembersAsync(user.account_key, list.id, user)
}
}
REQUEST_SELECT_ACCOUNT -> {
if (user == null) return
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
@Referral
val referral = arguments.getString(EXTRA_REFERRAL)
2016-08-20 04:30:54 +02:00
IntentUtils.openUserProfile(activity, accountKey, user.key, user.screen_name,
null, preferences.getBoolean(KEY_NEW_DOCUMENT_API), referral)
2016-06-29 15:47:52 +02:00
}
}
}
}
2016-12-11 07:29:00 +01:00
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_user, container, false)
2016-06-29 15:47:52 +02:00
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val activity = activity
userColorNameManager.registerColorChangedListener(this)
userColorNameManager.registerNicknameChangedListener(this)
2016-08-20 04:30:54 +02:00
nameFirst = preferences.getBoolean(KEY_NAME_FIRST)
locale = resources.configuration.locale
cardBackgroundColor = ThemeUtils.getCardBackgroundColor(activity,
2016-06-29 15:47:52 +02:00
ThemeUtils.getThemeBackgroundOption(activity),
ThemeUtils.getUserThemeBackgroundAlpha(activity))
2016-08-20 04:30:54 +02:00
actionBarShadowColor = 0xA0000000.toInt()
2016-06-29 15:47:52 +02:00
val args = arguments
2016-07-14 14:00:27 +02:00
val accountId: UserKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val userId: UserKey? = args.getParcelable<UserKey>(EXTRA_USER_KEY)
val screenName: String? = args.getString(EXTRA_SCREEN_NAME)
2016-06-29 15:47:52 +02:00
Utils.setNdefPushMessageCallback(activity, CreateNdefMessageCallback {
val user = user ?: return@CreateNdefMessageCallback null
NdefMessage(arrayOf(NdefRecord.createUri(LinkCreator.getUserWebLink(user))))
})
userFragmentView.setWindowInsetsListener { left, top, right, bottom ->
2016-08-09 09:48:16 +02:00
profileContentContainer.setPadding(0, top, 0, 0)
2016-07-02 06:05:23 +02:00
profileBannerSpace.statusBarHeight = top
2016-06-29 15:47:52 +02:00
2016-07-02 06:05:23 +02:00
if (profileBannerSpace.toolbarHeight == 0) {
2016-06-29 15:47:52 +02:00
var toolbarHeight = toolbar.measuredHeight
if (toolbarHeight == 0) {
toolbarHeight = ThemeUtils.getActionBarHeight(context)
}
2016-07-02 06:05:23 +02:00
profileBannerSpace.toolbarHeight = toolbarHeight
2016-06-29 15:47:52 +02:00
}
}
2016-08-09 09:48:16 +02:00
profileContentContainer.setOnSizeChangedListener { view, w, h, oldw, oldh ->
2016-06-29 15:47:52 +02:00
val toolbarHeight = toolbar.measuredHeight
2016-08-09 09:48:16 +02:00
userProfileDrawer.setPadding(0, toolbarHeight, 0, 0)
2016-07-02 06:05:23 +02:00
profileBannerSpace.toolbarHeight = toolbarHeight
2016-06-29 15:47:52 +02:00
}
2016-08-09 09:48:16 +02:00
userProfileDrawer.setDrawerCallback(this)
2016-06-29 15:47:52 +02:00
pagerAdapter = SupportTabsAdapter(activity, childFragmentManager)
2016-07-02 06:05:23 +02:00
viewPager.offscreenPageLimit = 3
viewPager.adapter = pagerAdapter
toolbarTabs.setViewPager(viewPager)
toolbarTabs.setTabDisplayOption(TabPagerIndicator.LABEL)
toolbarTabs.setOnPageChangeListener(this)
2016-06-29 15:47:52 +02:00
followContainer.follow.setOnClickListener(this)
2016-07-02 06:05:23 +02:00
profileImage.setOnClickListener(this)
profileBanner.setOnClickListener(this)
listedContainer.setOnClickListener(this)
groupsContainer.setOnClickListener(this)
followersContainer.setOnClickListener(this)
friendsContainer.setOnClickListener(this)
2016-06-29 15:47:52 +02:00
errorIcon.setOnClickListener(this)
2016-07-02 06:05:23 +02:00
profileBirthdayBanner.setOnClickListener(this)
profileBanner.setOnSizeChangedListener(this)
profileBannerSpace.setOnTouchListener(this)
2016-06-29 15:47:52 +02:00
2016-08-20 04:30:54 +02:00
profileNameBackground.setBackgroundColor(cardBackgroundColor)
profileDetailsContainer.setBackgroundColor(cardBackgroundColor)
toolbarTabs.setBackgroundColor(cardBackgroundColor)
2016-06-29 15:47:52 +02:00
val actionBarElevation = ThemeUtils.getSupportActionBarElevation(activity)
ViewCompat.setElevation(toolbarTabs, actionBarElevation)
setupBaseActionBar()
setupUserPages()
getUserInfo(accountId, userId, screenName, false)
}
override fun onStart() {
super.onStart()
bus.register(this)
@Referral
val referral = arguments.getString(EXTRA_REFERRAL)
val context = context
2016-08-20 04:30:54 +02:00
if (userEvent == null) {
userEvent = UserEvent.create(context, referral)
2016-06-29 15:47:52 +02:00
} else {
2016-08-20 04:30:54 +02:00
userEvent!!.markStart(context)
2016-06-29 15:47:52 +02:00
}
}
override fun onStop() {
val context = context
2016-08-20 04:30:54 +02:00
if (userEvent != null && context != null && user != null) {
userEvent!!.setUser(user!!)
userEvent!!.markEnd()
2016-12-06 06:15:22 +01:00
HotMobiLogger.getInstance(context).log(userEvent!!)
2016-06-29 15:47:52 +02:00
}
bus.unregister(this)
super.onStop()
}
override fun onResume() {
super.onResume()
2016-08-20 04:30:54 +02:00
setUiColor(uiColor)
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
override fun onSaveInstanceState(outState: Bundle) {
outState.putParcelable(EXTRA_USER, user)
2016-06-29 15:47:52 +02:00
super.onSaveInstanceState(outState)
}
override fun onDestroyView() {
user = null
2016-08-20 04:30:54 +02:00
relationship = null
2016-06-29 15:47:52 +02:00
val lm = loaderManager
lm.destroyLoader(LOADER_ID_USER)
lm.destroyLoader(LOADER_ID_FRIENDSHIP)
super.onDestroyView()
}
2016-12-11 07:29:00 +01:00
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_user_profile, menu)
2016-06-29 15:47:52 +02:00
}
@UiThread
2016-12-11 07:29:00 +01:00
override fun onPrepareOptionsMenu(menu: Menu) {
2016-07-02 06:05:23 +02:00
val user = user ?: return
2016-11-26 09:13:00 +01:00
val account = this.account
2016-06-29 15:47:52 +02:00
val isMyself = user.account_key.maybeEquals(user.key)
2016-12-11 07:29:00 +01:00
val mentionItem = menu.findItem(R.id.mention)
2016-06-29 15:47:52 +02:00
if (mentionItem != null) {
val displayName = UserColorNameManager.decideDisplayName(user.nickname,
2016-08-20 04:30:54 +02:00
user.name, user.screen_name, nameFirst)
2016-06-29 15:47:52 +02:00
mentionItem.title = getString(R.string.mention_user_name, displayName)
}
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.mention, !isMyself)
MenuUtils.setItemAvailability(menu, R.id.incoming_friendships, isMyself)
MenuUtils.setItemAvailability(menu, R.id.saved_searches, isMyself)
2016-11-26 09:13:00 +01:00
MenuUtils.setItemAvailability(menu, R.id.blocked_users, isMyself)
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.block, !isMyself)
2016-11-26 09:13:00 +01:00
val isTwitter: Boolean
if (account != null) {
2016-12-04 06:45:57 +01:00
isTwitter = AccountType.TWITTER == account.type
2016-06-29 15:47:52 +02:00
} else {
2016-11-26 09:13:00 +01:00
isTwitter = false
2016-06-29 15:47:52 +02:00
}
2016-11-26 09:13:00 +01:00
MenuUtils.setItemAvailability(menu, R.id.add_to_list, isTwitter)
MenuUtils.setItemAvailability(menu, R.id.mute_user, !isMyself && isTwitter)
MenuUtils.setItemAvailability(menu, R.id.muted_users, isMyself && isTwitter)
MenuUtils.setItemAvailability(menu, R.id.report_spam, !isMyself && isTwitter)
MenuUtils.setItemAvailability(menu, R.id.enable_retweets, !isMyself && isTwitter)
2016-08-20 04:30:54 +02:00
val userRelationship = relationship
2016-06-29 15:47:52 +02:00
if (userRelationship != null) {
val filterItem = menu.findItem(R.id.add_to_filter)
if (filterItem != null) {
filterItem.isChecked = userRelationship.filtering
}
if (isMyself) {
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, false)
2016-06-29 15:47:52 +02:00
} else {
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, userRelationship.can_dm)
MenuUtils.setItemAvailability(menu, R.id.block, true)
2016-06-29 15:47:52 +02:00
val blockItem = menu.findItem(R.id.block)
if (blockItem != null) {
ActionIconDrawable.setMenuHighlight(blockItem, TwidereMenuInfo(userRelationship.blocking))
blockItem.setTitle(if (userRelationship.blocking) R.string.unblock else R.string.block)
}
val muteItem = menu.findItem(R.id.mute_user)
if (muteItem != null) {
muteItem.isChecked = userRelationship.muting
}
val wantRetweetsItem = menu.findItem(R.id.enable_retweets)
if (wantRetweetsItem != null) {
wantRetweetsItem.isChecked = userRelationship.retweet_enabled
}
}
} else {
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, false)
2016-06-29 15:47:52 +02:00
}
val intent = Intent(INTENT_ACTION_EXTENSION_OPEN_USER)
val extras = Bundle()
extras.putParcelable(EXTRA_USER, user)
intent.putExtras(extras)
menu.removeGroup(MENU_GROUP_USER_EXTENSION)
MenuUtils.addIntentToMenu(activity, menu, intent, MENU_GROUP_USER_EXTENSION)
val drawer = userProfileDrawer
if (drawer != null) {
val offset = drawer.paddingTop - drawer.headerTop
2016-12-11 07:29:00 +01:00
previousActionBarItemIsDark = 0
previousTabItemIsDark = 0
2016-06-29 15:47:52 +02:00
updateScrollOffset(offset)
}
}
2016-12-11 07:29:00 +01:00
override fun onOptionsItemSelected(item: MenuItem): Boolean {
2016-06-29 15:47:52 +02:00
val context = context
val twitter = twitterWrapper
val user = user
2016-08-20 04:30:54 +02:00
val userRelationship = relationship
2016-06-29 15:47:52 +02:00
if (user == null) return false
2016-12-11 07:29:00 +01:00
when (item.itemId) {
2016-06-29 15:47:52 +02:00
R.id.block -> {
if (userRelationship == null) return true
if (userRelationship.blocking) {
twitter.destroyBlockAsync(user.account_key, user.key)
} else {
CreateUserBlockDialogFragment.show(fragmentManager, user)
}
}
R.id.report_spam -> {
ReportSpamDialogFragment.show(fragmentManager, user)
}
R.id.add_to_filter -> {
if (userRelationship == null) return true
2016-12-13 01:23:41 +01:00
val cr = context.contentResolver
2016-06-29 15:47:52 +02:00
if (userRelationship.filtering) {
val where = Expression.equalsArgs(Filters.Users.USER_KEY).sql
val whereArgs = arrayOf(user.key.toString())
2016-07-02 06:05:23 +02:00
cr.delete(Filters.Users.CONTENT_URI, where, whereArgs)
2016-06-29 15:47:52 +02:00
Utils.showInfoMessage(activity, R.string.message_user_unmuted, false)
2016-12-11 07:29:00 +01:00
getFriendship()
2016-06-29 15:47:52 +02:00
} else {
2016-12-11 07:29:00 +01:00
AddUserFilterDialogFragment.show(fragmentManager, user)
2016-06-29 15:47:52 +02:00
}
}
R.id.mute_user -> {
if (userRelationship == null) return true
if (userRelationship.muting) {
twitter.destroyMuteAsync(user.account_key, user.key)
} else {
CreateUserMuteDialogFragment.show(fragmentManager, user)
}
}
R.id.mention -> {
val intent = Intent(INTENT_ACTION_MENTION)
val bundle = Bundle()
bundle.putParcelable(EXTRA_USER, user)
intent.putExtras(bundle)
startActivity(intent)
}
R.id.send_direct_message -> {
val builder = Uri.Builder()
builder.scheme(SCHEME_TWIDERE)
builder.authority(AUTHORITY_DIRECT_MESSAGES_CONVERSATION)
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, user.account_key.toString())
builder.appendQueryParameter(QUERY_PARAM_USER_KEY, user.key.toString())
val intent = Intent(Intent.ACTION_VIEW, builder.build())
2016-12-04 06:45:57 +01:00
intent.putExtra(EXTRA_ACCOUNT, AccountUtils.getAccountDetails(AccountManager.get(activity), user.account_key))
2016-06-29 15:47:52 +02:00
intent.putExtra(EXTRA_USER, user)
startActivity(intent)
}
R.id.set_color -> {
val intent = Intent(activity, ColorPickerDialogActivity::class.java)
intent.putExtra(EXTRA_COLOR, userColorNameManager.getUserColor(user.key))
intent.putExtra(EXTRA_ALPHA_SLIDER, false)
intent.putExtra(EXTRA_CLEAR_BUTTON, true)
startActivityForResult(intent, REQUEST_SET_COLOR)
}
R.id.clear_nickname -> {
userColorNameManager.clearUserNickname(user.key)
}
R.id.set_nickname -> {
val nick = userColorNameManager.getUserNickname(user.key)
SetUserNicknameDialogFragment.show(fragmentManager, user.key, nick)
}
R.id.add_to_list -> {
2016-08-30 14:23:59 +02:00
promiseOnUi {
executeAfterFragmentResumed {
ProgressDialogFragment.show(fragmentManager, "get_list_progress")
}
}.then {
2016-12-06 06:15:22 +01:00
val microBlog = MicroBlogAPIFactory.getInstance(context, user.account_key)
val paging = Paging()
val ownedLists = microBlog.getUserListOwnerships(paging)
var nextCursor = ownedLists.nextCursor
while (nextCursor != 0L) {
val list = microBlog.getUserListOwnerships(paging)
ownedLists.addAll(list)
nextCursor = list.nextCursor
}
2016-08-30 14:23:59 +02:00
val userListMemberships = microBlog.getUserListMemberships(user.key.id, null, true)
return@then Array<ParcelableUserList>(ownedLists.size) { idx ->
val list = ParcelableUserListUtils.from(ownedLists[idx], user.account_key)
list.is_user_inside = userListMemberships.firstOrNull { it.id == ownedLists[idx].id } != null
return@Array list
}
}.alwaysUi {
executeAfterFragmentResumed {
val df = fragmentManager.findFragmentByTag("get_list_progress") as? DialogFragment
df?.dismiss()
}
}.successUi { result ->
executeAfterFragmentResumed {
val df = AddRemoveUserListDialogFragment()
df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = user.account_key
this[EXTRA_USER_KEY] = user.key
this[EXTRA_USER_LISTS] = result
}
df.show(fragmentManager, "add_remove_list")
}
}.failUi {
Utils.showErrorMessage(context, R.string.action_getting_user_lists, it, false)
}
2016-06-29 15:47:52 +02:00
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
intent.setClass(activity, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
intent.putExtra(EXTRA_ACCOUNT_HOST, user.key.host)
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
}
R.id.follow -> {
if (userRelationship == null) return true
val updatingRelationship = twitter.isUpdatingRelationship(user.account_key,
user.key)
if (!updatingRelationship) {
if (userRelationship.following) {
DestroyFriendshipDialogFragment.show(fragmentManager, user)
} else {
twitter.createFriendshipAsync(user.account_key, user.key)
}
}
return true
}
R.id.enable_retweets -> {
val newState = !item.isChecked
val update = FriendshipUpdate()
update.retweets(newState)
2016-07-05 15:19:51 +02:00
twitter.updateFriendship(user.account_key, user.key, update)
2016-06-29 15:47:52 +02:00
item.isChecked = newState
return true
}
R.id.muted_users -> {
IntentUtils.openMutesUsers(activity, user.account_key)
return true
}
R.id.blocked_users -> {
IntentUtils.openUserBlocks(activity, user.account_key)
return true
}
R.id.incoming_friendships -> {
IntentUtils.openIncomingFriendships(activity, user.account_key)
return true
}
R.id.user_mentions -> {
IntentUtils.openUserMentions(context, user.account_key, user.screen_name)
return true
}
R.id.saved_searches -> {
IntentUtils.openSavedSearches(context, user.account_key)
return true
}
R.id.scheduled_statuses -> {
IntentUtils.openScheduledStatuses(context, user.account_key)
return true
}
R.id.open_in_browser -> {
val uri = LinkCreator.getUserWebLink(user)
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addCategory(Intent.CATEGORY_BROWSABLE)
intent.`package` = IntentUtils.getDefaultBrowserPackage(context, uri, true)
if (intent.resolveActivity(context.packageManager) != null) {
startActivity(intent)
}
return true
}
else -> {
val intent = item.intent
if (intent != null && intent.resolveActivity(context.packageManager) != null) {
startActivity(intent)
}
}
}
return true
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val host = host
if (host is AppCompatActivity) {
host.setSupportActionBar(toolbar)
}
}
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event, metaState)) return true
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
if (action != null) {
when (action) {
ACTION_NAVIGATION_PREVIOUS_TAB -> {
val previous = viewPager.currentItem - 1
2016-12-11 07:29:00 +01:00
if (previous >= 0 && previous < pagerAdapter.count) {
2016-07-02 06:05:23 +02:00
viewPager.setCurrentItem(previous, true)
2016-06-29 15:47:52 +02:00
}
return true
}
ACTION_NAVIGATION_NEXT_TAB -> {
val next = viewPager.currentItem + 1
2016-12-11 07:29:00 +01:00
if (next >= 0 && next < pagerAdapter.count) {
2016-07-02 06:05:23 +02:00
viewPager.setCurrentItem(next, true)
2016-06-29 15:47:52 +02:00
}
return true
}
}
}
return handler.handleKey(activity, null, keyCode, event, metaState)
}
override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
if (isFragmentKeyboardShortcutHandled(handler, keyCode, event, metaState)) return true
val action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
if (action != null) {
when (action) {
ACTION_NAVIGATION_PREVIOUS_TAB, ACTION_NAVIGATION_NEXT_TAB -> return true
}
}
return false
}
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
keyCode: Int, repeatCount: Int,
event: KeyEvent, metaState: Int): Boolean {
return handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
}
private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
keyCode: Int, repeatCount: Int, event: KeyEvent, metaState: Int): Boolean {
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
}
return false
}
private fun handleFragmentKeyboardShortcutSingle(handler: KeyboardShortcutsHandler,
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutSingle(handler, keyCode, event, metaState)
}
return false
}
private fun isFragmentKeyboardShortcutHandled(handler: KeyboardShortcutsHandler,
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.isKeyboardShortcutHandled(handler, keyCode, event, metaState)
}
return false
}
private val keyboardShortcutRecipient: Fragment?
get() = currentVisibleFragment
override fun fitSystemWindows(insets: Rect) {
}
override fun setupWindow(activity: FragmentActivity): Boolean {
if (activity is AppCompatActivity) {
activity.supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
activity.supportRequestWindowFeature(WindowCompat.FEATURE_ACTION_MODE_OVERLAY)
}
WindowSupport.setStatusBarColor(activity.window, Color.TRANSPARENT)
return true
}
override fun onClick(view: View) {
val activity = activity
val user = user
if (activity == null || user == null) return
when (view.id) {
R.id.errorContainer -> {
getUserInfo(true)
}
R.id.follow -> {
if (user.account_key.maybeEquals(user.key)) {
IntentUtils.openProfileEditor(getActivity(), user.account_key)
} else {
2016-08-20 04:30:54 +02:00
val userRelationship = relationship
2016-06-29 15:47:52 +02:00
val twitter = twitterWrapper
if (userRelationship == null) return
if (userRelationship.blocking) {
twitter.destroyBlockAsync(user.account_key, user.key)
} else if (userRelationship.following) {
DestroyFriendshipDialogFragment.show(fragmentManager, user)
} else {
twitter.createFriendshipAsync(user.account_key, user.key)
}
}
}
2016-07-02 06:05:23 +02:00
R.id.profileImage -> {
2016-06-29 15:47:52 +02:00
val url = Utils.getOriginalTwitterProfileImage(user.profile_image_url)
val profileImage = ParcelableMediaUtils.image(url)
profileImage.type = ParcelableMedia.Type.IMAGE
val media = arrayOf(profileImage)
IntentUtils.openMedia(activity, user.account_key, false, null, media, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API))
}
R.id.profileBanner -> {
val bannerUrl = ParcelableUserUtils.getProfileBannerUrl(user) ?: return
val url = InternalTwitterContentUtils.getBestBannerUrl(bannerUrl,
Integer.MAX_VALUE)
val profileBanner = ParcelableMediaUtils.image(url)
profileBanner.type = ParcelableMedia.Type.IMAGE
val media = arrayOf(profileBanner)
IntentUtils.openMedia(activity, user.account_key, false, null, media, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API))
}
R.id.listedContainer -> {
IntentUtils.openUserLists(getActivity(), user.account_key, user.key,
user.screen_name)
}
R.id.groupsContainer -> {
IntentUtils.openUserGroups(getActivity(), user.account_key, user.key,
user.screen_name)
}
R.id.followersContainer -> {
IntentUtils.openUserFollowers(getActivity(), user.account_key, user.key,
user.screen_name)
}
R.id.friendsContainer -> {
IntentUtils.openUserFriends(getActivity(), user.account_key, user.key,
user.screen_name)
}
2016-07-02 06:05:23 +02:00
R.id.nameContainer -> {
2016-06-29 15:47:52 +02:00
if (user.account_key == user.key) return
IntentUtils.openProfileEditor(getActivity(), user.account_key)
}
R.id.profileBirthdayBanner -> {
2016-12-11 07:29:00 +01:00
hideBirthdayView = true
2016-07-02 06:05:23 +02:00
profileBirthdayBanner.startAnimation(AnimationUtils.loadAnimation(getActivity(), android.R.anim.fade_out))
profileBirthdayBanner.visibility = View.GONE
2016-06-29 15:47:52 +02:00
}
}
}
2016-07-16 09:27:46 +02:00
override fun onLinkClick(link: String, orig: String?, accountKey: UserKey?,
2016-06-29 15:47:52 +02:00
extraId: Long, type: Int, sensitive: Boolean,
start: Int, end: Int): Boolean {
val user = user ?: return false
when (type) {
TwidereLinkify.LINK_TYPE_MENTION -> {
IntentUtils.openUserProfile(activity, user.account_key, null, link, null,
preferences.getBoolean(KEY_NEW_DOCUMENT_API), Referral.USER_MENTION)
return true
}
TwidereLinkify.LINK_TYPE_HASHTAG -> {
2016-07-16 09:27:46 +02:00
IntentUtils.openTweetSearch(activity, user.account_key, "#" + link)
2016-06-29 15:47:52 +02:00
return true
}
TwidereLinkify.LINK_TYPE_LINK_IN_TEXT, TwidereLinkify.LINK_TYPE_ENTITY_URL -> {
val uri = Uri.parse(link)
val intent: Intent
if (uri.scheme != null) {
intent = Intent(Intent.ACTION_VIEW, uri)
} else {
intent = Intent(Intent.ACTION_VIEW, uri.buildUpon().scheme("http").build())
}
startActivity(intent)
return true
}
TwidereLinkify.LINK_TYPE_LIST -> {
2016-08-25 04:10:53 +02:00
val mentionList = link.split("/").dropLastWhile(String::isEmpty)
2016-07-16 09:27:46 +02:00
if (mentionList.size != 2) {
2016-06-29 15:47:52 +02:00
return false
}
return true
}
}
return false
}
override fun onUserNicknameChanged(userId: UserKey, nick: String) {
if (user == null || user!!.key != userId) return
displayUser(user, account)
2016-06-29 15:47:52 +02:00
}
override fun onUserColorChanged(userId: UserKey, color: Int) {
if (user == null || user!!.key != userId) return
displayUser(user, account)
2016-06-29 15:47:52 +02:00
}
override fun onSizeChanged(view: View, w: Int, h: Int, oldw: Int, oldh: Int) {
2016-12-11 07:29:00 +01:00
bannerWidth = w
2016-06-29 15:47:52 +02:00
if (w != oldw || h != oldh) {
requestFitSystemWindows()
}
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
2016-07-02 06:05:23 +02:00
if (profileBirthdayBanner.visibility == View.VISIBLE) {
return profileBirthdayBanner.dispatchTouchEvent(event)
2016-06-29 15:47:52 +02:00
}
2016-07-02 06:05:23 +02:00
return profileBanner.dispatchTouchEvent(event)
2016-06-29 15:47:52 +02:00
}
override fun scrollToStart(): Boolean {
2016-12-06 06:15:22 +01:00
val fragment = currentVisibleFragment as? RefreshScrollTopInterface ?: return false
2016-06-29 15:47:52 +02:00
fragment.scrollToStart()
return true
}
override fun triggerRefresh(): Boolean {
2016-12-06 06:15:22 +01:00
val fragment = currentVisibleFragment as? RefreshScrollTopInterface ?: return false
2016-06-29 15:47:52 +02:00
fragment.triggerRefresh()
return true
}
private fun getFriendship() {
val user = user ?: return
2016-08-20 04:30:54 +02:00
relationship = null
2016-06-29 15:47:52 +02:00
val lm = loaderManager
lm.destroyLoader(LOADER_ID_FRIENDSHIP)
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, user.account_key)
args.putParcelable(EXTRA_USER, user)
2016-12-11 07:29:00 +01:00
if (!getFriendShipLoaderInitialized) {
lm.initLoader(LOADER_ID_FRIENDSHIP, args, friendshipLoaderCallbacks)
2016-12-11 07:29:00 +01:00
getFriendShipLoaderInitialized = true
2016-06-29 15:47:52 +02:00
} else {
lm.restartLoader(LOADER_ID_FRIENDSHIP, args, friendshipLoaderCallbacks)
2016-06-29 15:47:52 +02:00
}
}
private fun getUserInfo(omitIntentExtra: Boolean) {
val user = this.user ?: return
getUserInfo(user.account_key, user.key, user.screen_name, omitIntentExtra)
}
private fun setUiColor(color: Int) {
2016-08-20 04:30:54 +02:00
uiColor = color
2016-12-11 07:29:00 +01:00
previousActionBarItemIsDark = 0
previousTabItemIsDark = 0
if (actionBarBackground == null) {
2016-06-29 15:47:52 +02:00
setupBaseActionBar()
}
val activity = activity as BaseActivity
if (Config.coloredActionBar(activity, activity.ateKey)) {
2016-12-11 07:29:00 +01:00
primaryColor = color
primaryColorDark = ThemeUtils.computeDarkColor(color)
2016-06-29 15:47:52 +02:00
} else {
2016-12-11 07:29:00 +01:00
primaryColor = Config.primaryColor(activity, activity.ateKey)
primaryColorDark = Color.BLACK
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
if (actionBarBackground != null) {
actionBarBackground!!.color = primaryColor
2016-06-29 15:47:52 +02:00
}
val taskColor: Int
if (Config.coloredActionBar(activity, activity.ateKey)) {
taskColor = color
} else {
taskColor = Config.toolbarColor(activity, activity.ateKey, toolbar)
}
if (user != null) {
2016-08-20 04:30:54 +02:00
val name = userColorNameManager.getDisplayName(user, nameFirst)
2016-06-29 15:47:52 +02:00
ActivitySupport.setTaskDescription(activity, TaskDescriptionCompat(name, null, taskColor))
} else {
ActivitySupport.setTaskDescription(activity, TaskDescriptionCompat(null, null, taskColor))
}
val optimalAccentColor = ThemeUtils.getOptimalAccentColor(color,
descriptionContainer.description.currentTextColor)
descriptionContainer.description.setLinkTextColor(optimalAccentColor)
locationContainer.location.setLinkTextColor(optimalAccentColor)
urlContainer.url.setLinkTextColor(optimalAccentColor)
profileBanner.setBackgroundColor(color)
2016-12-11 07:29:00 +01:00
toolbarTabs.setBackgroundColor(primaryColor)
2016-06-29 15:47:52 +02:00
val drawer = userProfileDrawer
if (drawer != null) {
val offset = drawer.paddingTop - drawer.headerTop
updateScrollOffset(offset)
}
}
private fun setupBaseActionBar() {
2016-12-06 06:15:22 +01:00
val activity = activity as? LinkHandlerActivity ?: return
2016-06-29 15:47:52 +02:00
val actionBar = activity.supportActionBar ?: return
2016-12-11 07:29:00 +01:00
val shadow = ResourcesCompat.getDrawable(activity.resources, R.drawable.shadow_user_banner_action_bar, null)!!
actionBarBackground = ActionBarDrawable(shadow)
2016-06-29 15:47:52 +02:00
if (!ThemeUtils.isWindowFloating(activity) && ThemeUtils.isTransparentBackground(activity.currentThemeBackgroundOption)) {
// mActionBarBackground.setAlpha(ThemeUtils.getActionBarAlpha(linkHandler.getCurrentThemeBackgroundAlpha()));
2016-07-02 06:05:23 +02:00
profileBanner.alpha = activity.currentThemeBackgroundAlpha / 255f
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
actionBar.setBackgroundDrawable(actionBarBackground)
2016-06-29 15:47:52 +02:00
}
private fun setupUserPages() {
val args = arguments
val tabArgs = Bundle()
val user = args.getParcelable<ParcelableUser>(EXTRA_USER)
if (user != null) {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, user.account_key)
tabArgs.putParcelable(EXTRA_USER_KEY, user.key)
tabArgs.putString(EXTRA_SCREEN_NAME, user.screen_name)
} else {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, args.getParcelable<Parcelable>(EXTRA_ACCOUNT_KEY))
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable<Parcelable>(EXTRA_USER_KEY))
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME))
}
2016-12-11 07:29:00 +01:00
pagerAdapter.addTab(cls = UserTimelineFragment::class.java, args = tabArgs, name = getString(R.string.statuses),
2016-11-30 08:18:43 +01:00
icon = DrawableHolder.resource(R.drawable.ic_action_quote), type = TAB_TYPE_STATUSES, position = TAB_POSITION_STATUSES)
2016-12-11 07:29:00 +01:00
pagerAdapter.addTab(cls = UserMediaTimelineFragment::class.java, args = tabArgs, name = getString(R.string.media),
2016-11-30 08:18:43 +01:00
icon = DrawableHolder.resource(R.drawable.ic_action_gallery), type = TAB_TYPE_MEDIA, position = TAB_POSITION_MEDIA)
2016-06-29 15:47:52 +02:00
if (preferences.getBoolean(KEY_I_WANT_MY_STARS_BACK)) {
2016-12-11 07:29:00 +01:00
pagerAdapter.addTab(cls = UserFavoritesFragment::class.java, args = tabArgs, name = getString(R.string.favorites),
2016-11-30 08:18:43 +01:00
icon = DrawableHolder.resource(R.drawable.ic_action_star), type = TAB_TYPE_FAVORITES, position = TAB_POSITION_FAVORITES)
2016-06-29 15:47:52 +02:00
} else {
2016-12-11 07:29:00 +01:00
pagerAdapter.addTab(cls = UserFavoritesFragment::class.java, args = tabArgs, name = getString(R.string.likes),
2016-11-30 08:18:43 +01:00
icon = DrawableHolder.resource(R.drawable.ic_action_heart), type = TAB_TYPE_FAVORITES, position = TAB_POSITION_FAVORITES)
2016-06-29 15:47:52 +02:00
}
}
private fun updateScrollOffset(offset: Int) {
2016-12-11 07:29:00 +01:00
val spaceHeight = profileBannerSpace.height
2016-06-29 15:47:52 +02:00
val factor = TwidereMathUtils.clamp(if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat(), 0f, 1f)
2016-12-11 07:29:00 +01:00
profileBannerContainer.translationY = (-offset).toFloat()
profileBanner.translationY = (offset / 2).toFloat()
profileBirthdayBanner.translationY = (offset / 2).toFloat()
2016-06-29 15:47:52 +02:00
val activity = activity as BaseActivity
val statusBarColor = sArgbEvaluator.evaluate(factor, 0xA0000000.toInt(),
2016-12-11 07:29:00 +01:00
ThemeUtils.computeDarkColor(primaryColorDark)) as Int
2016-06-29 15:47:52 +02:00
val window = activity.window
2016-12-11 07:29:00 +01:00
userFragmentView.setStatusBarColor(statusBarColor)
2016-06-29 15:47:52 +02:00
ThemeUtils.setLightStatusBar(window, ThemeUtils.isLightColor(statusBarColor))
2016-12-11 07:29:00 +01:00
val stackedTabColor = primaryColor
2016-06-29 15:47:52 +02:00
2016-07-02 06:05:23 +02:00
val profileContentHeight = (profileNameContainer!!.height + profileDetailsContainer.height).toFloat()
2016-06-29 15:47:52 +02:00
val tabOutlineAlphaFactor: Float
if (offset - spaceHeight > 0) {
tabOutlineAlphaFactor = 1f - TwidereMathUtils.clamp((offset - spaceHeight) / profileContentHeight, 0f, 1f)
} else {
tabOutlineAlphaFactor = 1f
}
2016-12-11 07:29:00 +01:00
actionBarBackground?.apply {
this.factor = factor
this.outlineAlphaFactor = tabOutlineAlphaFactor
2016-06-29 15:47:52 +02:00
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
2016-12-11 07:29:00 +01:00
windowOverlay.alpha = factor * tabOutlineAlphaFactor
2016-06-29 15:47:52 +02:00
}
val currentTabColor = sArgbEvaluator.evaluate(tabOutlineAlphaFactor,
2016-08-20 04:30:54 +02:00
stackedTabColor, cardBackgroundColor) as Int
2016-06-29 15:47:52 +02:00
2016-07-02 06:05:23 +02:00
val tabBackground = toolbarTabs.background
2016-06-29 15:47:52 +02:00
(tabBackground as ColorDrawable).color = currentTabColor
val tabItemIsDark = ThemeUtils.isLightColor(currentTabColor)
2016-12-11 07:29:00 +01:00
if (previousTabItemIsDark == 0 || (if (tabItemIsDark) 1 else -1) != previousTabItemIsDark) {
2016-06-29 15:47:52 +02:00
val tabContrastColor = ThemeUtils.getColorDependent(currentTabColor)
2016-07-02 06:05:23 +02:00
toolbarTabs.setIconColor(tabContrastColor)
toolbarTabs.setLabelColor(tabContrastColor)
2016-06-29 15:47:52 +02:00
if (Config.coloredActionBar(activity, activity.ateKey)) {
2016-07-02 06:05:23 +02:00
toolbarTabs.setStripColor(tabContrastColor)
2016-06-29 15:47:52 +02:00
} else {
2016-08-20 04:30:54 +02:00
toolbarTabs.setStripColor(ThemeUtils.getOptimalAccentColor(uiColor,
2016-06-29 15:47:52 +02:00
tabContrastColor))
}
2016-07-02 06:05:23 +02:00
toolbarTabs.updateAppearance()
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
previousTabItemIsDark = if (tabItemIsDark) 1 else -1
2016-06-29 15:47:52 +02:00
2016-08-20 04:30:54 +02:00
val currentActionBarColor = sArgbEvaluator.evaluate(factor, actionBarShadowColor,
2016-06-29 15:47:52 +02:00
stackedTabColor) as Int
val actionItemIsDark = ThemeUtils.isLightColor(currentActionBarColor)
2016-12-11 07:29:00 +01:00
if (previousActionBarItemIsDark == 0 || (if (actionItemIsDark) 1 else -1) != previousActionBarItemIsDark) {
2016-06-29 15:47:52 +02:00
ThemeUtils.applyToolbarItemColor(activity, toolbar, currentActionBarColor)
}
2016-12-11 07:29:00 +01:00
previousActionBarItemIsDark = if (actionItemIsDark) 1 else -1
2016-06-29 15:47:52 +02:00
updateTitleAlpha()
}
private fun updateTitleAlpha() {
val location = IntArray(2)
profileNameContainer.name.getLocationInWindow(location)
val nameShowingRatio = (userProfileDrawer.paddingTop - location[1]) / profileNameContainer.name.height.toFloat()
val textAlpha = TwidereMathUtils.clamp(nameShowingRatio, 0f, 1f)
val titleView = ViewSupport.findViewByText(toolbar, toolbar.title)
if (titleView != null) {
titleView.alpha = textAlpha
}
val subtitleView = ViewSupport.findViewByText(toolbar, toolbar.subtitle)
if (subtitleView != null) {
subtitleView.alpha = textAlpha
}
}
override var controlBarOffset: Float
2016-12-11 07:29:00 +01:00
get() = 0f
set(value) = Unit //Ignore
2016-06-29 15:47:52 +02:00
override val controlBarHeight: Int
2016-12-11 07:29:00 +01:00
get() = 0
2016-06-29 15:47:52 +02:00
2016-08-19 16:25:27 +02:00
override val shouldInitLoader: Boolean
get() = user != null
2016-06-29 15:47:52 +02:00
private class ActionBarDrawable(shadow: Drawable) : LayerDrawable(arrayOf(shadow, ActionBarColorDrawable.create(true))) {
2016-12-11 07:29:00 +01:00
private val shadowDrawable: Drawable
private val colorDrawable: ColorDrawable
private var alphaValue: Int = 0
var factor: Float = 0f
set(value) {
field = value
updateValue()
}
2016-06-29 15:47:52 +02:00
var color: Int = 0
set(value) {
field = value
2016-12-11 07:29:00 +01:00
colorDrawable.color = value
updateValue()
}
var outlineAlphaFactor: Float = 0f
set(value) {
field = value
updateValue()
2016-06-29 15:47:52 +02:00
}
init {
2016-12-11 07:29:00 +01:00
shadowDrawable = getDrawable(0)
colorDrawable = getDrawable(1) as ColorDrawable
2016-06-29 15:47:52 +02:00
alpha = 0xFF
2016-12-11 07:29:00 +01:00
updateValue()
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
override fun setAlpha(alpha: Int) {
alphaValue = alpha
updateValue()
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
override fun getAlpha(): Int {
return alphaValue
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
override fun getOutline(outline: Outline) {
colorDrawable.getOutline(outline)
outline.alpha = factor * outlineAlphaFactor * 0.99f
2016-06-29 15:47:52 +02:00
}
override fun getIntrinsicWidth(): Int {
2016-12-11 07:29:00 +01:00
return colorDrawable.intrinsicWidth
2016-06-29 15:47:52 +02:00
}
override fun getIntrinsicHeight(): Int {
2016-12-11 07:29:00 +01:00
return colorDrawable.intrinsicHeight
2016-06-29 15:47:52 +02:00
}
2016-12-11 07:29:00 +01:00
private fun updateValue() {
val shadowAlpha = Math.round(alpha * TwidereMathUtils.clamp(1 - factor, 0f, 1f))
shadowDrawable.alpha = shadowAlpha
2016-06-29 15:47:52 +02:00
val hasColor = color != 0
2016-12-11 07:29:00 +01:00
val colorAlpha = if (hasColor) Math.round(alpha * TwidereMathUtils.clamp(factor, 0f, 1f)) else 0
colorDrawable.alpha = colorAlpha
2016-06-29 15:47:52 +02:00
invalidateSelf()
}
}
internal class UserRelationshipLoader(
context: Context,
private val accountKey: UserKey?,
private val user: ParcelableUser?
2016-11-26 10:41:35 +01:00
) : AsyncTaskLoader<SingleResponse<ParcelableRelationship>>(context) {
2016-06-29 15:47:52 +02:00
2016-11-26 10:41:35 +01:00
override fun loadInBackground(): SingleResponse<ParcelableRelationship> {
2016-06-29 15:47:52 +02:00
if (accountKey == null || user == null) {
2016-11-26 10:41:35 +01:00
return SingleResponse.Companion.getInstance<ParcelableRelationship>(MicroBlogException("Null parameters"))
2016-06-29 15:47:52 +02:00
}
val userKey = user.key
val isFiltering = DataStoreUtils.isFilteringUser(context, userKey)
if (accountKey == user.key) {
2016-11-26 10:41:35 +01:00
return SingleResponse.getInstance(ParcelableRelationshipUtils.create(accountKey, userKey,
2016-06-29 15:47:52 +02:00
null, isFiltering))
}
2016-12-04 06:45:57 +01:00
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
2016-11-26 10:41:35 +01:00
accountKey) ?: return SingleResponse.getInstance<ParcelableRelationship>(MicroBlogException("No Account"))
2016-12-04 06:45:57 +01:00
if (details.type == AccountType.TWITTER) {
2016-06-29 15:47:52 +02:00
if (!UserKeyUtils.isSameHost(accountKey, user.key)) {
2016-11-26 10:41:35 +01:00
return SingleResponse.getInstance(ParcelableRelationshipUtils.create(user, isFiltering))
2016-06-29 15:47:52 +02:00
}
}
2016-12-06 06:15:22 +01:00
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey) ?: return SingleResponse.Companion.getInstance<ParcelableRelationship>(MicroBlogException("No Account"))
2016-06-29 15:47:52 +02:00
try {
val relationship = twitter.showFriendship(user.key.id)
if (relationship.isSourceBlockingTarget || relationship.isSourceBlockedByTarget) {
Utils.setLastSeen(context, userKey, -1)
} else {
Utils.setLastSeen(context, userKey, System.currentTimeMillis())
}
2016-11-26 10:41:35 +01:00
val data = ParcelableRelationshipUtils.create(accountKey, userKey, relationship,
isFiltering)
val resolver = context.contentResolver
val values = ParcelableRelationshipValuesCreator.create(data)
resolver.insert(CachedRelationships.CONTENT_URI, values)
return SingleResponse.getInstance(data)
2016-06-29 15:47:52 +02:00
} catch (e: MicroBlogException) {
2016-11-26 10:41:35 +01:00
return SingleResponse.Companion.getInstance<ParcelableRelationship>(e)
2016-06-29 15:47:52 +02:00
}
}
override fun onStartLoading() {
forceLoad()
}
}
2016-11-26 10:41:35 +01:00
private fun ParcelableRelationship.check(user: ParcelableUser): Boolean {
if (account_key != user.account_key) {
return false
2016-06-29 15:47:52 +02:00
}
2016-11-26 10:41:35 +01:00
return user.extras != null && TextUtils.equals(user_key.id, user.extras.unique_id) || TextUtils.equals(user_key.id, user.key.id)
2016-06-29 15:47:52 +02:00
}
2016-08-30 14:23:59 +02:00
class AddRemoveUserListDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val lists = arguments.getParcelableArray(EXTRA_USER_LISTS).toTypedArray(ParcelableUserList.CREATOR)
val userKey = arguments.getParcelable<UserKey>(EXTRA_USER_KEY)
val accountKey = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.add_or_remove_from_list)
val entries = Array(lists.size) { idx ->
lists[idx].name
}
val states = BooleanArray(lists.size) { idx ->
lists[idx].is_user_inside
}
builder.setPositiveButton(android.R.string.ok, null)
builder.setNeutralButton(R.string.new_user_list, null)
builder.setNegativeButton(android.R.string.cancel, null)
builder.setMultiChoiceItems(entries, states, null)
val dialog = builder.create()
dialog.setOnShowListener {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val checkedPositions = dialog.listView.checkedItemPositions
promiseOnUi {
val activity = activity as IExtendedActivity
activity.executeAfterFragmentResumed {
ProgressDialogFragment.show(fragmentManager, "update_lists_progress")
}
}.then {
2016-12-06 06:15:22 +01:00
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey)
2016-08-30 14:23:59 +02:00
val successfulStates = SparseBooleanArray()
try {
for (i in 0 until checkedPositions.size()) {
val pos = checkedPositions.keyAt(i)
val checked = checkedPositions.valueAt(i)
if (states[pos] != checked) {
if (checked) {
twitter.addUserListMember(lists[pos].id, userKey.id)
} else {
twitter.deleteUserListMember(lists[pos].id, userKey.id)
}
successfulStates.put(pos, checked)
}
}
} catch (e: MicroBlogException) {
throw UpdateListsException(successfulStates)
}
}.alwaysUi {
val activity = activity as IExtendedActivity
activity.executeAfterFragmentResumed {
val df = fragmentManager.findFragmentByTag("update_lists_progress") as? DialogFragment
df?.dismiss()
}
}.successUi {
dismiss()
}.failUi { e ->
if (e is UpdateListsException) {
val successfulStates = e.successfulStates
for (i in 0 until successfulStates.size()) {
val pos = successfulStates.keyAt(i)
val checked = successfulStates.valueAt(i)
dialog.listView.setItemChecked(pos, checked)
states[pos] = checked
}
}
Utils.showErrorMessage(context, R.string.action_modifying_lists, e, false)
}
}
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
val df = CreateUserListDialogFragment()
df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey
}
df.show(fragmentManager, "create_user_list")
}
}
return dialog
}
class UpdateListsException(val successfulStates: SparseBooleanArray) : MicroBlogException()
}
2016-06-29 15:47:52 +02:00
companion object {
private val sArgbEvaluator = ArgbEvaluator()
private val LOADER_ID_USER = 1
private val LOADER_ID_FRIENDSHIP = 2
private val TAB_POSITION_STATUSES = 0
private val TAB_POSITION_MEDIA = 1
private val TAB_POSITION_FAVORITES = 2
private val TAB_TYPE_STATUSES = "statuses"
private val TAB_TYPE_MEDIA = "media"
private val TAB_TYPE_FAVORITES = "favorites"
}
}