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

1794 lines
77 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
2017-04-07 09:21:56 +02:00
import android.support.annotation.ColorRes
import android.support.annotation.DrawableRes
import android.support.annotation.StringRes
2016-06-29 15:47:52 +02:00
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
2017-04-07 09:21:56 +02:00
import android.support.v4.content.ContextCompat
2017-02-07 16:36:29 +01:00
import android.support.v4.content.FixedAsyncTaskLoader
2016-06-29 15:47:52 +02:00
import android.support.v4.content.Loader
import android.support.v4.content.res.ResourcesCompat
2017-01-03 14:22:20 +01:00
import android.support.v4.graphics.ColorUtils
2016-06-29 15:47:52 +02:00
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.Spanned
2016-06-29 15:47:52 +02:00
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 android.widget.Toast
2017-03-01 15:12:25 +01:00
import com.bumptech.glide.Glide
2016-06-29 15:47:52 +02:00
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.successUi
2016-12-18 06:21:24 +01:00
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
2017-01-07 15:45:33 +01:00
import org.mariotaku.kpreferences.get
2017-01-28 08:32:28 +01:00
import org.mariotaku.ktextension.*
2017-03-05 09:08:09 +01:00
import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.microblog.library.MicroBlog
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
import org.mariotaku.microblog.library.twitter.model.UserList
2016-06-29 15:47:52 +02:00
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
2017-03-01 02:11:56 +01:00
import org.mariotaku.twidere.activity.iface.IBaseActivity
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
2017-03-21 03:33:27 +01:00
import org.mariotaku.twidere.constant.*
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
2017-02-05 14:42:20 +01:00
import org.mariotaku.twidere.extension.applyTheme
2017-03-02 09:26:12 +01:00
import org.mariotaku.twidere.extension.loadOriginalProfileImage
import org.mariotaku.twidere.extension.loadProfileBanner
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.extension.model.getBestProfileBanner
2017-04-05 07:12:01 +02:00
import org.mariotaku.twidere.extension.model.urlPreferred
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.*
2017-02-09 09:00:12 +01:00
import org.mariotaku.twidere.model.event.FriendshipTaskEvent
import org.mariotaku.twidere.model.event.FriendshipUpdatedEvent
import org.mariotaku.twidere.model.event.ProfileUpdatedEvent
import org.mariotaku.twidere.model.event.TaskStateChangedEvent
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.model.util.*
import org.mariotaku.twidere.provider.TwidereDataStore.CachedRelationships
import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers
import org.mariotaku.twidere.text.TwidereURLSpan
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.lang.ref.WeakReference
2016-06-29 15:47:52 +02:00
import java.util.*
2017-01-12 17:26:44 +01:00
class UserFragment : BaseFragment(), OnClickListener, OnLinkClickListener,
2016-08-19 16:25:27 +02:00
OnSizeChangedListener, OnTouchListener, DrawerCallback, SupportFragmentCallback,
SystemWindowsInsetsCallback, RefreshScrollTopInterface, OnPageChangeListener,
KeyboardShortcutCallback, UserColorChangedListener, UserNicknameChangedListener,
IToolBarSupportFragment, StatusesFragmentDelegate, UserTimelineFragmentDelegate,
AbsContentRecyclerViewFragment.RefreshCompleteListener {
2016-08-19 16:25:27 +02:00
2016-06-29 15:47:52 +02:00
override val toolbar: Toolbar
get() = profileContentContainer.toolbar
2017-02-19 15:29:08 +01:00
private lateinit var profileBirthdayBanner: View
private lateinit var actionBarBackground: ActionBarDrawable
2016-12-11 07:29:00 +01:00
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-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>>,
2017-02-15 07:48:10 +01:00
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>>,
2017-02-15 07:48:10 +01:00
data: SingleResponse<ParcelableUser>) {
2016-06-29 15:47:52 +02:00
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?,
2017-02-15 07:48:10 +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)) {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_edit, R.color.material_light_blue,
R.string.action_edit)
2016-06-29 15:47:52 +02:00
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
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) {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_block, R.color.material_red,
R.string.action_unblock)
2016-12-24 06:48:01 +01:00
} else if (userRelationship.blocked_by) {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_block, R.color.material_grey,
R.string.action_block)
2016-06-29 15:47:52 +02:00
} else if (userRelationship.following) {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_confirm, R.color.material_light_blue,
R.string.action_unfollow)
2016-06-29 15:47:52 +02:00
} else if (user.is_follow_request_sent) {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_time, R.color.material_light_blue,
R.string.label_follow_request_sent)
2016-06-29 15:47:52 +02:00
} else {
2017-04-07 09:21:56 +02:00
setFollowEditButton(R.drawable.ic_action_add, android.R.color.white,
R.string.action_follow)
2016-06-29 15:47:52 +02:00
}
followingYouIndicator.visibility = if (userRelationship.followed_by) View.VISIBLE else View.GONE
2017-01-17 18:59:44 +01:00
val resolver = context.applicationContext.contentResolver
task {
2017-03-05 09:08:09 +01:00
resolver.insert(CachedUsers.CONTENT_URI, ObjectCursor.valuesCreatorFrom(ParcelableUser::class.java).create(user))
resolver.insert(CachedRelationships.CONTENT_URI, ObjectCursor.valuesCreatorFrom(ParcelableRelationship::class.java).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
}
2017-03-27 05:08:09 +02:00
val spec = pagerAdapter.get(viewPager.currentItem)
2016-06-29 15:47:52 +02:00
assert(spec.type != null)
when (spec.type) {
2017-03-27 05:08:09 +02:00
TAB_TYPE_STATUSES, TAB_TYPE_STATUSES_WITH_REPLIES -> {
2016-06-29 15:47:52 +02:00
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-12-18 06:21:24 +01:00
val theme = Chameleon.getOverrideTheme(activity, activity)
setUiColor(theme.colorPrimary)
2016-06-29 15:47:52 +02:00
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 (user.nickname.isNullOrEmpty()) {
user.name
} else {
getString(R.string.name_with_nickname, user.name, user.nickname)
})
2016-06-29 15:47:52 +02:00
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 linkHighlightOption = preferences[linkHighlightOptionKey]
val linkify = TwidereLinkify(this, linkHighlightOption)
2016-06-29 15:47:52 +02:00
if (user.description_unescaped != null) {
val text = SpannableStringBuilder.valueOf(user.description_unescaped).apply {
user.description_spans?.applyTo(this)
linkify.applyAllLinks(this, user.account_key, false, false)
}
2016-06-29 15:47:52 +02:00
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.location.text = user.location
locationContainer.visibility = if (locationContainer.location.empty) View.GONE else View.VISIBLE
2017-04-05 07:12:01 +02:00
urlContainer.url.text = user.urlPreferred?.let {
val ssb = SpannableStringBuilder(it)
ssb.setSpan(TwidereURLSpan(it, highlightStyle = linkHighlightOption), 0, ssb.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return@let ssb
}
urlContainer.visibility = if (urlContainer.url.empty) View.GONE else View.VISIBLE
if (user.created_at >= 0) {
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.visibility = View.VISIBLE
createdAtContainer.createdAt.text = resources.getQuantityString(R.plurals.created_at_with_N_tweets_per_day, dailyTweets,
createdAt, dailyTweets)
} else {
createdAtContainer.visibility = View.GONE
}
2017-03-04 05:26:14 +01:00
val locale = Locale.getDefault()
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
if (user.color != 0) {
setUiColor(user.color)
} else if (user.link_color != 0) {
setUiColor(user.link_color)
2016-12-18 06:21:24 +01:00
} else {
val theme = Chameleon.getOverrideTheme(activity, activity)
setUiColor(theme.colorPrimary)
2016-06-29 15:47:52 +02:00
}
val defWidth = resources.displayMetrics.widthPixels
2016-12-11 07:29:00 +01:00
val width = if (bannerWidth > 0) bannerWidth else defWidth
2017-03-02 09:26:12 +01:00
val requestManager = Glide.with(this)
requestManager.loadProfileBanner(context, user, width).into(profileBanner)
requestManager.loadOriginalProfileImage(context, user, profileImage.style,
profileImage.cornerRadius, profileImage.cornerRadiusRatio).into(profileImage)
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 userCreationDay = condition@ if (user.created_at >= 0) {
val cal = Calendar.getInstance()
val currentMonth = cal.get(Calendar.MONTH)
val currentDay = cal.get(Calendar.DAY_OF_MONTH)
cal.timeInMillis = user.created_at
cal.get(Calendar.MONTH) == currentMonth && cal.get(Calendar.DAY_OF_MONTH) == currentDay
} else {
false
}
2017-02-19 15:29:08 +01:00
if (userCreationDay && !hideBirthdayView) {
2017-02-19 15:29:08 +01:00
if (profileBirthdayStub != null) {
profileBirthdayBanner = profileBirthdayStub.inflate()
profileBirthdayBanner.setOnClickListener(this)
} else {
profileBirthdayBanner.visibility = View.VISIBLE
}
} else if (profileBirthdayStub == null) {
2016-07-02 06:05:23 +02:00
profileBirthdayBanner.visibility = View.GONE
2016-06-29 15:47:52 +02:00
}
2017-04-05 07:12:01 +02:00
urlContainer.url.movementMethod = null
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
2017-02-04 08:39:08 +01:00
return pagerAdapter.instantiateItem(viewPager, currentItem)
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?,
2017-02-15 07:48:10 +01:00
omitIntentExtra: Boolean) {
2016-06-29 15:47:52 +02:00
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,
2017-04-07 13:05:02 +02:00
user.extras.statusnet_profile_url, preferences[newDocumentApiKey],
referral, null)
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)
cardBackgroundColor = ThemeUtils.getCardBackgroundColor(activity,
2017-03-21 03:33:27 +01:00
preferences[themeBackgroundOptionKey], preferences[themeBackgroundAlphaKey])
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 { _, top, _, _ ->
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
}
}
profileContentContainer.setOnSizeChangedListener { _, _, _, _, _ ->
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.DisplayOption.LABEL)
2016-07-02 06:05:23 +02:00
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)
2017-04-05 07:12:01 +02:00
urlContainer.setOnClickListener(this)
2016-07-02 06:05:23 +02:00
profileBanner.setOnSizeChangedListener(this)
profileBannerSpace.setOnTouchListener(this)
2016-06-29 15:47:52 +02:00
userProfileSwipeLayout.setOnRefreshListener {
if (!triggerRefresh()) {
userProfileSwipeLayout.isRefreshing = false
}
}
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)
2017-02-19 15:29:08 +01:00
actionBarBackground = ActionBarDrawable(ResourcesCompat.getDrawable(activity.resources,
R.drawable.shadow_user_banner_action_bar, null)!!)
2016-06-29 15:47:52 +02:00
setupBaseActionBar()
2017-01-07 15:45:33 +01:00
setupViewStyle()
2016-06-29 15:47:52 +02:00
setupUserPages()
getUserInfo(accountId, userId, screenName, false)
}
2017-01-07 15:45:33 +01:00
2016-06-29 15:47:52 +02:00
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) {
val user = this.user ?: return
2016-11-26 09:13:00 +01:00
val account = this.account
val relationship = this.relationship
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)
2017-04-03 16:55:41 +02:00
MenuUtils.setItemAvailability(menu, R.id.qr_code, isMyself)
2016-07-04 03:31:17 +02:00
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)
if (relationship != null) {
menu.findItem(R.id.add_to_filter)?.apply {
isChecked = relationship.filtering
2016-06-29 15:47:52 +02:00
}
2016-06-29 15:47:52 +02:00
if (isMyself) {
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, false)
MenuUtils.setItemAvailability(menu, R.id.enable_notifications, false)
2016-06-29 15:47:52 +02:00
} else {
MenuUtils.setItemAvailability(menu, R.id.send_direct_message, relationship.can_dm)
2016-07-04 03:31:17 +02:00
MenuUtils.setItemAvailability(menu, R.id.block, true)
MenuUtils.setItemAvailability(menu, R.id.enable_notifications, isTwitter && relationship.following)
menu.findItem(R.id.block)?.apply {
ActionIconDrawable.setMenuHighlight(this, TwidereMenuInfo(relationship.blocking))
this.setTitle(if (relationship.blocking) R.string.action_unblock else R.string.action_block)
}
menu.findItem(R.id.mute_user)?.apply {
isChecked = relationship.muting
}
menu.findItem(R.id.enable_retweets)?.apply {
isChecked = relationship.retweet_enabled
}
menu.findItem(R.id.enable_notifications)?.apply {
isChecked = relationship.notifications_enabled
2016-06-29 15:47:52 +02:00
}
}
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, false)
MenuUtils.setItemAvailability(menu, R.id.enable_notifications, 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
if (userRelationship.filtering) {
2016-12-28 06:17:24 +01:00
DataStoreUtils.removeFromFilter(context, listOf(user))
2017-01-27 08:43:25 +01:00
Utils.showInfoMessage(activity, R.string.message_toast_user_filters_removed, 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)
2017-02-15 07:48:10 +01:00
builder.authority(AUTHORITY_MESSAGES)
builder.path(PATH_MESSAGES_CONVERSATION_NEW)
2016-06-29 15:47:52 +02:00
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-15 06:11:32 +01:00
intent.putExtra(EXTRA_ACCOUNT, AccountUtils.getAccountDetails(AccountManager.get(activity), user.account_key, true))
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 -> {
2017-03-22 13:00:29 +01:00
executeAfterFragmentResumed {
ProgressDialogFragment.show(it.fragmentManager, "get_list_progress")
2016-08-30 14:23:59 +02:00
}.then {
fun MicroBlog.getUserListOwnerMemberships(id: String): ArrayList<UserList> {
val result = ArrayList<UserList>()
var nextCursor: Long
val paging = Paging()
paging.count(100)
do {
2017-03-04 05:26:14 +01:00
val resp = getUserListMemberships(id, paging, true)
result.addAll(resp)
nextCursor = resp.nextCursor
paging.cursor(nextCursor)
} while (nextCursor > 0)
return result
}
2016-12-06 06:15:22 +01:00
val microBlog = MicroBlogAPIFactory.getInstance(context, user.account_key)
val ownedLists = ArrayList<ParcelableUserList>()
val listMemberships = microBlog.getUserListOwnerMemberships(user.key.id)
val paging = Paging()
paging.count(100)
var nextCursor: Long
do {
val resp = microBlog.getUserListOwnerships(paging)
resp.mapTo(ownedLists) { item ->
val userList = ParcelableUserListUtils.from(item, user.account_key)
userList.is_user_inside = listMemberships.any { it.id == item.id }
return@mapTo userList
}
nextCursor = resp.nextCursor
paging.cursor(nextCursor)
} while (nextCursor > 0)
return@then ownedLists.toTypedArray()
2016-08-30 14:23:59 +02:00
}.alwaysUi {
executeAfterFragmentResumed {
val df = fragmentManager.findFragmentByTag("get_list_progress") as? DialogFragment
df?.dismiss()
}
}.successUi { result ->
executeAfterFragmentResumed { fragment ->
2016-08-30 14:23:59 +02:00
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(fragment.fragmentManager, "add_remove_list")
2016-08-30 14:23:59 +02:00
}
}.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.enable_notifications -> {
val newState = !item.isChecked
if (newState) {
Toast.makeText(context, R.string.message_toast_notification_enabled_hint,
Toast.LENGTH_SHORT).show()
}
val update = FriendshipUpdate()
update.deviceNotifications(newState)
twitter.updateFriendship(user.account_key, user.key, update)
item.isChecked = newState
return true
}
2016-06-29 15:47:52 +02:00
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.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)
}
2017-04-03 16:55:41 +02:00
return true
}
R.id.qr_code -> {
executeAfterFragmentResumed {
val df = UserQRDialogFragment()
df.arguments = Bundle {
this[EXTRA_USER] = user
}
df.show(it.childFragmentManager, "user_qr_code")
}
2016-06-29 15:47:52 +02:00
return true
}
else -> {
val intent = item.intent
if (intent != null && intent.resolveActivity(context.packageManager) != null) {
startActivity(intent)
}
}
}
return true
}
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,
2017-02-15 07:48:10 +01:00
keyCode: Int, repeatCount: Int,
event: KeyEvent, metaState: Int): Boolean {
2016-06-29 15:47:52 +02:00
return handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
}
private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, repeatCount: Int, event: KeyEvent, metaState: Int): Boolean {
2016-06-29 15:47:52 +02:00
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
}
return false
}
private fun handleFragmentKeyboardShortcutSingle(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
2016-06-29 15:47:52 +02:00
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutSingle(handler, keyCode, event, metaState)
}
return false
}
private fun isFragmentKeyboardShortcutHandled(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
2016-06-29 15:47:52 +02:00
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)
2016-12-24 06:48:01 +01:00
} else if (userRelationship.blocked_by) {
CreateUserBlockDialogFragment.show(childFragmentManager, user)
2016-06-29 15:47:52 +02:00
} 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)
2017-01-20 15:08:42 +01:00
IntentUtils.openMedia(activity, user.account_key, media, null, false,
preferences[newDocumentApiKey], preferences[displaySensitiveContentsKey])
2016-06-29 15:47:52 +02:00
}
R.id.profileBanner -> {
val url = user.getBestProfileBanner(Integer.MAX_VALUE) ?: return
2016-06-29 15:47:52 +02:00
val profileBanner = ParcelableMediaUtils.image(url)
profileBanner.type = ParcelableMedia.Type.IMAGE
val media = arrayOf(profileBanner)
2017-01-20 15:08:42 +01:00
IntentUtils.openMedia(activity, user.account_key, media, null, false,
preferences[newDocumentApiKey], preferences[displaySensitiveContentsKey])
2016-06-29 15:47:52 +02:00
}
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)
}
2017-04-05 07:12:01 +02:00
R.id.urlContainer -> {
val url = user.urlPreferred ?: return
OnLinkClickHandler.openLink(context, preferences, url)
}
2016-06-29 15:47:52 +02:00
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?,
2017-02-15 07:48:10 +01:00
extraId: Long, type: Int, sensitive: Boolean,
start: Int, end: Int): Boolean {
2016-06-29 15:47:52 +02:00
val user = user ?: return false
when (type) {
TwidereLinkify.LINK_TYPE_MENTION -> {
2017-04-07 13:05:02 +02:00
IntentUtils.openUserProfile(activity, user.account_key, null, link, null,
preferences[newDocumentApiKey], Referral.USER_MENTION, null)
2016-06-29 15:47:52 +02:00
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 {
2017-02-19 15:29:08 +01:00
if (profileBirthdayStub == null && profileBirthdayBanner.visibility == View.VISIBLE) {
2016-07-02 06:05:23 +02:00
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
}
override fun onRefreshComplete(fragment: AbsContentRecyclerViewFragment<*, *>) {
userProfileSwipeLayout.isRefreshing = false
}
2016-06-29 15:47:52 +02:00
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
2017-03-04 05:26:14 +01:00
setupBaseActionBar()
2016-06-29 15:47:52 +02:00
val activity = activity as BaseActivity
2016-12-18 06:21:24 +01:00
val theme = Chameleon.getOverrideTheme(activity, activity)
2016-12-18 03:32:11 +01:00
if (theme.isToolbarColored) {
2016-12-11 07:29:00 +01:00
primaryColor = color
2016-06-29 15:47:52 +02:00
} else {
primaryColor = theme.colorToolbar
2016-06-29 15:47:52 +02:00
}
primaryColorDark = ChameleonUtils.darkenColor(primaryColor)
2017-03-04 05:26:14 +01:00
actionBarBackground.color = primaryColor
2016-06-29 15:47:52 +02:00
val taskColor: Int
2016-12-18 03:32:11 +01:00
if (theme.isToolbarColored) {
2017-01-03 14:22:20 +01:00
taskColor = ColorUtils.setAlphaComponent(color, 0xFF)
2016-06-29 15:47:52 +02:00
} else {
2017-01-03 14:22:20 +01:00
taskColor = ColorUtils.setAlphaComponent(theme.colorToolbar, 0xFF)
2016-06-29 15:47:52 +02:00
}
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
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
}
2017-01-07 15:45:33 +01:00
private fun setupViewStyle() {
profileImage.style = preferences[profileImageStyleKey]
2017-01-28 08:32:28 +01:00
val lightFont = preferences[lightFontKey]
profileNameContainer.name.applyFontFamily(lightFont)
profileNameContainer.screenName.applyFontFamily(lightFont)
profileNameContainer.followingYouIndicator.applyFontFamily(lightFont)
descriptionContainer.description.applyFontFamily(lightFont)
urlContainer.url.applyFontFamily(lightFont)
locationContainer.location.applyFontFamily(lightFont)
createdAtContainer.createdAt.applyFontFamily(lightFont)
2017-01-07 15:45:33 +01:00
}
2016-06-29 15:47:52 +02:00
private fun setupUserPages() {
val args = arguments
val tabArgs = Bundle()
val user = args.getParcelable<ParcelableUser>(EXTRA_USER)
2017-03-27 15:56:03 +02:00
val userKey: UserKey?
2016-06-29 15:47:52 +02:00
if (user != null) {
2017-03-27 15:56:03 +02:00
userKey = user.account_key
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userKey)
2016-06-29 15:47:52 +02:00
tabArgs.putParcelable(EXTRA_USER_KEY, user.key)
tabArgs.putString(EXTRA_SCREEN_NAME, user.screen_name)
2017-04-07 13:05:02 +02:00
tabArgs.putString(EXTRA_PROFILE_URL, user.extras?.statusnet_profile_url)
2016-06-29 15:47:52 +02:00
} else {
2017-03-27 15:56:03 +02:00
userKey = args.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userKey)
2016-06-29 15:47:52 +02:00
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable<Parcelable>(EXTRA_USER_KEY))
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME))
2017-04-07 13:05:02 +02:00
tabArgs.putString(EXTRA_PROFILE_URL, args.getString(EXTRA_PROFILE_URL))
2016-06-29 15:47:52 +02:00
}
pagerAdapter.add(cls = UserTimelineFragment::class.java, args = Bundle(tabArgs).apply {
this[UserTimelineFragment.EXTRA_ENABLE_TIMELINE_FILTER] = true
}, name = getString(R.string.title_statuses), type = TAB_TYPE_STATUSES,
position = TAB_POSITION_STATUSES)
2017-03-27 05:08:09 +02:00
pagerAdapter.add(cls = UserMediaTimelineFragment::class.java, args = tabArgs,
name = getString(R.string.media), 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)) {
2017-03-27 05:08:09 +02:00
pagerAdapter.add(cls = UserFavoritesFragment::class.java, args = tabArgs,
name = getString(R.string.title_favorites), type = TAB_TYPE_FAVORITES,
position = TAB_POSITION_FAVORITES)
2016-06-29 15:47:52 +02:00
} else {
2017-03-27 05:08:09 +02:00
pagerAdapter.add(cls = UserFavoritesFragment::class.java, args = tabArgs,
name = getString(R.string.title_likes), 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
2017-02-04 11:42:14 +01:00
val factor = (if (spaceHeight == 0) 0f else offset / spaceHeight.toFloat()).coerceIn(0f, 1f)
2016-12-11 07:29:00 +01:00
profileBannerContainer.translationY = (-offset).toFloat()
profileBanner.translationY = (offset / 2).toFloat()
2017-02-19 15:29:08 +01:00
if (profileBirthdayStub == null) {
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) {
2017-02-04 11:42:14 +01:00
tabOutlineAlphaFactor = 1f - ((offset - spaceHeight) / profileContentHeight).coerceIn(0f, 1f)
2016-06-29 15:47:52 +02:00
} else {
tabOutlineAlphaFactor = 1f
}
2017-03-04 05:26:14 +01:00
actionBarBackground.apply {
2016-12-11 07:29:00 +01:00
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-12-18 06:21:24 +01:00
val theme = Chameleon.getOverrideTheme(activity, activity)
2016-12-18 03:32:11 +01:00
if (theme.isToolbarColored) {
2016-07-02 06:05:23 +02:00
toolbarTabs.setStripColor(tabContrastColor)
2016-06-29 15:47:52 +02:00
} else {
2016-12-18 03:32:11 +01:00
toolbarTabs.setStripColor(ThemeUtils.getOptimalAccentColor(uiColor, tabContrastColor))
2016-06-29 15:47:52 +02:00
}
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()
}
2017-04-07 09:21:56 +02:00
override var controlBarOffset: Float
get() = 0f
set(value) = Unit //Ignore
override val controlBarHeight: Int
get() = 0
override val shouldInitLoader: Boolean
get() = user != null
2016-06-29 15:47:52 +02:00
private fun updateTitleAlpha() {
val location = IntArray(2)
profileNameContainer.name.getLocationInWindow(location)
val nameShowingRatio = (userProfileDrawer.paddingTop - location[1]) / profileNameContainer.name.height.toFloat()
2017-02-04 11:42:14 +01:00
val textAlpha = nameShowingRatio.coerceIn(0f, 1f)
2016-06-29 15:47:52 +02:00
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
}
}
2017-04-07 09:21:56 +02:00
private fun ParcelableRelationship.check(user: ParcelableUser): Boolean {
if (account_key != user.account_key) {
return false
}
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
2017-04-07 09:21:56 +02:00
private fun setFollowEditButton(@DrawableRes icon: Int, @ColorRes color: Int, @StringRes label: Int) {
followContainer.follow.setImageResource(icon)
ViewCompat.setBackgroundTintList(followContainer.follow, ContextCompat.getColorStateList(context, color))
followContainer.follow.contentDescription = getString(label)
}
2016-06-29 15:47:52 +02:00
private class ActionBarDrawable(shadow: Drawable) : LayerDrawable(arrayOf(shadow, ActionBarColorDrawable.create(true))) {
2017-02-19 15:29:08 +01:00
private val shadowDrawable = getDrawable(0)
private val colorDrawable = getDrawable(1) as ColorDrawable
2016-12-11 07:29:00 +01:00
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 {
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() {
2017-02-04 11:42:14 +01:00
val shadowAlpha = Math.round(alpha * (1 - factor).coerceIn(0f, 1f))
2016-12-11 07:29:00 +01:00
shadowDrawable.alpha = shadowAlpha
2016-06-29 15:47:52 +02:00
val hasColor = color != 0
2017-02-04 11:42:14 +01:00
val colorAlpha = if (hasColor) Math.round(alpha * factor.coerceIn(0f, 1f)) else 0
2016-12-11 07:29:00 +01:00
colorDrawable.alpha = colorAlpha
2016-06-29 15:47:52 +02:00
invalidateSelf()
}
}
2017-04-07 09:21:56 +02:00
2016-06-29 15:47:52 +02:00
internal class UserRelationshipLoader(
context: Context,
private val accountKey: UserKey?,
private val user: ParcelableUser?
2017-02-07 16:36:29 +01:00
) : FixedAsyncTaskLoader<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-12-15 06:11:32 +01:00
accountKey, true) ?: 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
2017-03-05 09:08:09 +01:00
val values = ObjectCursor.valuesCreatorFrom(ParcelableRelationship::class.java).create(data)
2016-11-26 10:41:35 +01:00
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-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.title_add_or_remove_from_list)
2016-08-30 14:23:59 +02:00
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()
2017-02-05 14:42:20 +01:00
dialog.setOnShowListener { dialog ->
dialog as AlertDialog
dialog.applyTheme()
2016-08-30 14:23:59 +02:00
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val checkedPositions = dialog.listView.checkedItemPositions
val weakActivity = WeakReference(activity)
2017-03-22 13:00:29 +01:00
(activity as IBaseActivity<*>).executeAfterFragmentResumed {
ProgressDialogFragment.show(it.supportFragmentManager, "update_lists_progress")
2016-08-30 14:23:59 +02:00
}.then {
val activity = weakActivity.get() ?: throw IllegalStateException()
val twitter = MicroBlogAPIFactory.getInstance(activity, 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 {
2017-03-01 02:11:56 +01:00
val activity = weakActivity.get() as? IBaseActivity<*> ?: return@alwaysUi
activity.executeAfterFragmentResumed { activity ->
val manager = activity.supportFragmentManager
val df = manager.findFragmentByTag("update_lists_progress") as? DialogFragment
2016-08-30 14:23:59 +02:00
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"
2017-03-27 05:08:09 +02:00
private val TAB_TYPE_STATUSES_WITH_REPLIES = "statuses_with_replies"
2016-06-29 15:47:52 +02:00
private val TAB_TYPE_MEDIA = "media"
private val TAB_TYPE_FAVORITES = "favorites"
}
}