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

1920 lines
82 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
2017-04-13 05:18:12 +02:00
import android.annotation.SuppressLint
2016-06-29 15:47:52 +02:00
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.PorterDuff
2016-06-29 15:47:52 +02:00
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
2020-01-26 08:35:15 +01:00
import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.annotation.UiThread
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.core.content.ContextCompat
import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.ColorUtils
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.ViewCompat
import androidx.viewpager.widget.ViewPager
2020-01-26 08:35:15 +01:00
import androidx.core.view.WindowCompat
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar
2016-06-29 15:47:52 +02:00
import android.text.SpannableStringBuilder
import android.text.Spanned
2016-06-29 15:47:52 +02:00
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
2017-05-13 08:19:23 +02:00
import android.widget.TextView
import android.widget.Toast
2016-06-29 15:47:52 +02:00
import com.squareup.otto.Subscribe
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
2017-04-22 09:18:44 +02:00
import org.mariotaku.microblog.library.mastodon.Mastodon
2016-06-29 15:47:52 +02:00
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
import org.mariotaku.microblog.library.twitter.model.Paging
import org.mariotaku.microblog.library.twitter.model.UserList
2020-05-31 08:11:38 +02:00
import org.mariotaku.twidere.BuildConfig
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
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-04-20 14:04:37 +02:00
import org.mariotaku.twidere.extension.*
2017-04-22 09:18:44 +02:00
import org.mariotaku.twidere.extension.model.*
import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable
2017-04-21 12:01:54 +02:00
import org.mariotaku.twidere.extension.model.api.microblog.toParcelable
2016-08-19 16:25:27 +02:00
import org.mariotaku.twidere.fragment.AbsStatusesFragment.StatusesFragmentDelegate
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowInsetsCallback
2016-06-29 15:47:52 +02:00
import org.mariotaku.twidere.fragment.iface.IToolBarSupportFragment
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
2017-04-21 14:24:15 +02:00
import org.mariotaku.twidere.fragment.statuses.UserFavoritesFragment
import org.mariotaku.twidere.fragment.statuses.UserMediaTimelineFragment
import org.mariotaku.twidere.fragment.statuses.UserTimelineFragment
2016-06-29 15:47:52 +02:00
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
2017-04-22 09:18:44 +02:00
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.model.util.ParcelableMediaUtils
import org.mariotaku.twidere.model.util.ParcelableRelationshipUtils
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.shortcut.ShortcutCreator
2016-06-29 15:47:52 +02:00
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.*
2020-06-09 00:50:51 +02:00
import kotlin.math.max
import kotlin.math.roundToInt
2016-06-29 15:47:52 +02:00
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,
SystemWindowInsetsCallback, RefreshScrollTopInterface, ViewPager.OnPageChangeListener,
2016-08-19 16:25:27 +02:00
KeyboardShortcutCallback, UserColorChangedListener, UserNicknameChangedListener,
IToolBarSupportFragment, StatusesFragmentDelegate,
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
2017-09-01 12:17:01 +02:00
private var systemWindowsInsets: Rect = Rect()
private var userInfoLoaderInitialized: Boolean = false
private var friendShipLoaderInitialized: Boolean = false
2016-12-11 07:29:00 +01:00
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-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
2020-01-26 08:35:15 +01:00
override fun onCreateLoader(id: Int, args: Bundle?): Loader<SingleResponse<ParcelableRelationship>> {
activity!!.invalidateOptionsMenu()
val accountKey = args?.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val user = args?.getParcelable<ParcelableUser>(EXTRA_USER)
2016-06-29 15:47:52 +02:00
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
}
2020-01-26 08:35:15 +01:00
return UserRelationshipLoader(activity!!, accountKey, user)
2016-06-29 15:47:52 +02:00
}
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>>,
2020-01-26 08:35:15 +01:00
data: SingleResponse<ParcelableRelationship>) {
2016-12-11 07:29:00 +01:00
followProgress.visibility = View.GONE
2017-04-13 05:18:12 +02:00
displayRelationship(data.data)
2016-06-29 15:47:52 +02:00
updateOptionsMenuVisibility()
}
}
private val userInfoLoaderCallbacks = object : LoaderCallbacks<SingleResponse<ParcelableUser>> {
2016-06-29 15:47:52 +02:00
2020-01-26 08:35:15 +01:00
override fun onCreateLoader(id: Int, args: Bundle?): Loader<SingleResponse<ParcelableUser>> {
val omitIntentExtra = args!!.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
2017-04-12 14:58:08 +02:00
val accountKey = args.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
val userKey = args.getParcelable<UserKey?>(EXTRA_USER_KEY)
2016-06-29 15:47:52 +02:00
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
2017-04-12 14:58:08 +02:00
val loadFromCache = user == null || !user.is_cache && user.key.maybeEquals(userKey)
2020-01-26 08:35:15 +01:00
return ParcelableUserLoader(activity!!, accountKey, userKey, screenName, arguments,
2016-06-29 15:47:52 +02:00
omitIntentExtra, loadFromCache)
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableUser>>) {
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUser>>,
2020-01-26 08:35:15 +01:00
data: SingleResponse<ParcelableUser>) {
2016-06-29 15:47:52 +02:00
val activity = activity ?: return
2020-06-09 02:21:48 +02:00
when {
data.data != null -> {
val user = data.data
cardContent.visibility = View.VISIBLE
errorContainer.visibility = View.GONE
progressContainer.visibility = View.GONE
val account: AccountDetails = data.extras.getParcelable(EXTRA_ACCOUNT)!!
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()
2016-06-29 15:47:52 +02:00
}
2020-06-09 02:21:48 +02:00
user?.is_cache == true -> {
cardContent.visibility = View.VISIBLE
errorContainer.visibility = View.GONE
progressContainer.visibility = View.GONE
displayUser(user, account)
updateOptionsMenuVisibility()
}
else -> {
if (data.hasException()) {
errorText.text = data.exception?.getErrorMessage(activity)
errorText.visibility = View.VISIBLE
}
cardContent.visibility = View.GONE
errorContainer.visibility = View.VISIBLE
progressContainer.visibility = View.GONE
displayUser(null, null)
updateOptionsMenuVisibility()
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
}
2017-04-13 05:18:12 +02:00
private fun displayRelationship(relationship: ParcelableRelationship?) {
val user = this.user ?: run {
this.relationship = null
2016-06-29 15:47:52 +02:00
return
}
2017-04-13 05:18:12 +02:00
if (user.key.maybeEquals(user.account_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
2017-04-13 05:18:12 +02:00
this.relationship = relationship
2016-06-29 15:47:52 +02:00
return
}
2017-04-13 05:18:12 +02:00
if (relationship == null || !relationship.check(user)) {
this.relationship = null
2016-06-29 15:47:52 +02:00
return
} else {
2017-04-13 05:18:12 +02:00
this.relationship = relationship
2016-06-29 15:47:52 +02:00
}
2020-01-26 08:35:15 +01:00
activity?.invalidateOptionsMenu()
2017-10-02 15:22:26 +02:00
when {
relationship.blocked_by -> {
pagesErrorContainer.visibility = View.GONE
pagesErrorText.text = null
pagesContent.visibility = View.VISIBLE
}
!relationship.following && user.hide_protected_contents -> {
pagesErrorContainer.visibility = View.VISIBLE
pagesErrorText.setText(R.string.user_protected_summary)
pagesErrorIcon.setImageResource(R.drawable.ic_info_locked)
pagesContent.visibility = View.GONE
}
else -> {
pagesErrorContainer.visibility = View.GONE
pagesErrorText.text = null
pagesContent.visibility = View.VISIBLE
}
2016-06-29 15:47:52 +02:00
}
2017-10-02 15:22:26 +02:00
when {
relationship.blocking -> setFollowEditButton(R.drawable.ic_action_block, R.color.material_red,
2017-04-07 09:21:56 +02:00
R.string.action_unblock)
2017-10-02 15:22:26 +02:00
relationship.blocked_by -> setFollowEditButton(R.drawable.ic_action_block, R.color.material_grey,
2017-04-07 09:21:56 +02:00
R.string.action_block)
2017-10-02 15:22:26 +02:00
relationship.following -> setFollowEditButton(R.drawable.ic_action_confirm, R.color.material_light_blue,
2017-04-07 09:21:56 +02:00
R.string.action_unfollow)
2017-10-02 15:22:26 +02:00
user.is_follow_request_sent -> setFollowEditButton(R.drawable.ic_action_time, R.color.material_light_blue,
2017-04-07 09:21:56 +02:00
R.string.label_follow_request_sent)
2017-10-02 15:22:26 +02:00
else -> setFollowEditButton(R.drawable.ic_action_add, android.R.color.white,
2017-04-07 09:21:56 +02:00
R.string.action_follow)
2016-06-29 15:47:52 +02:00
}
2017-04-13 05:18:12 +02:00
followingYouIndicator.visibility = if (relationship.followed_by) View.VISIBLE else View.GONE
2016-06-29 15:47:52 +02:00
2020-01-26 08:35:15 +01:00
context?.applicationContext?.contentResolver?.let { resolver ->
task {
resolver.insert(CachedUsers.CONTENT_URI, user, ParcelableUser::class.java)
resolver.insert(CachedRelationships.CONTENT_URI, relationship, ParcelableRelationship::class.java)
}
}
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()
}
override fun onPageScrollStateChanged(state: Int) {
2020-06-08 23:07:20 +02:00
userProfileSwipeLayout.isEnabled = state == ViewPager.SCROLL_STATE_IDLE
2016-06-29 15:47:52 +02:00
}
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
2017-09-08 13:40:12 +02:00
if (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)
2017-05-13 08:19:23 +02:00
profileNameContainer.name.setText(bidiFormatter.unicodeWrap(when {
user.nickname.isNullOrEmpty() -> user.name
else -> getString(R.string.name_with_nickname, user.name, user.nickname)
}), TextView.BufferType.SPANNABLE)
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
}
2017-04-13 05:18:12 +02:00
@SuppressLint("SetTextI18n")
2017-05-13 08:19:23 +02:00
profileNameContainer.screenName.spannable = "@${user.acct}"
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)
}
2017-05-13 08:19:23 +02:00
descriptionContainer.description.spannable = text
2016-06-29 15:47:52 +02:00
} else {
2017-05-13 08:19:23 +02:00
descriptionContainer.description.spannable = user.description_plain
2016-06-29 15:47:52 +02:00
Linkify.addLinks(descriptionContainer.description, Linkify.WEB_URLS)
}
2017-05-13 08:19:23 +02:00
descriptionContainer.hideIfEmpty(descriptionContainer.description)
2016-06-29 15:47:52 +02:00
2017-05-13 08:19:23 +02:00
locationContainer.location.spannable = user.location
locationContainer.visibility = if (locationContainer.location.empty) View.GONE else View.VISIBLE
2017-05-13 08:19:23 +02:00
urlContainer.url.spannable = user.urlPreferred?.let {
val ssb = SpannableStringBuilder(it)
ssb.setSpan(TwidereURLSpan(it, highlightStyle = linkHighlightOption), 0, ssb.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
return@let ssb
}
2017-05-13 08:19:23 +02:00
urlContainer.hideIfEmpty(urlContainer.url)
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()
2020-06-09 00:50:51 +02:00
val dailyTweets = (user.statuses_count / max(1f, daysSinceCreation)).roundToInt()
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)
2017-04-25 17:54:18 +02:00
groupsContainer.groupsCount.text = Utils.getLocalizedNumber(locale, user.groups_count)
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
2017-04-25 17:54:18 +02:00
groupsContainer.visibility = if (user.groups_count < 0) View.GONE else View.VISIBLE
2016-06-29 15:47:52 +02:00
2020-06-09 02:21:48 +02:00
when {
user.color != 0 -> {
setUiColor(user.color)
}
user.link_color != 0 -> {
setUiColor(user.link_color)
}
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
2020-01-26 08:35:15 +01:00
context?.let { requestManager.loadProfileBanner(it, user, width).into(profileBanner) }
context?.let {
requestManager.loadOriginalProfileImage(it, user, profileImage.style,
2017-04-12 08:12:45 +02:00
profileImage.cornerRadius, profileImage.cornerRadiusRatio)
2020-01-26 08:35:15 +01:00
.thumbnail(requestManager.loadProfileImage(it, user, profileImage.style,
2017-04-12 08:12:45 +02:00
profileImage.cornerRadius, profileImage.cornerRadiusRatio,
getString(R.string.profile_image_size))).into(profileImage)
2020-01-26 08:35:15 +01:00
}
2016-08-20 04:30:54 +02:00
val relationship = relationship
2016-06-29 15:47:52 +02:00
if (relationship == null) {
getFriendship()
}
2017-05-13 08:19:23 +02:00
activity.title = SpannableStringBuilder.valueOf(UserColorNameManager.decideDisplayName(user.nickname, user.name,
user.screen_name, nameFirst)).also {
externalThemeManager.emoji?.applyTo(it)
}
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
}
2017-06-26 08:48:05 +02:00
override fun getSystemWindowInsets(caller: Fragment, insets: Rect): Boolean {
2017-06-26 16:23:41 +02:00
insetsCallback?.getSystemWindowInsets(this, insets)
insets.top = 0
return true
2016-06-29 15:47:52 +02:00
}
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)
2017-09-01 12:17:01 +02:00
if (!userInfoLoaderInitialized) {
lm.initLoader(LOADER_ID_USER, args, userInfoLoaderCallbacks)
2017-09-01 12:17:01 +02:00
userInfoLoaderInitialized = 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) {
2020-01-26 08:35:15 +01:00
activity?.invalidateOptionsMenu()
2016-06-29 15:47:52 +02:00
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
2017-09-08 13:40:12 +02:00
val user = user ?: return
val accountKey = user.account_key ?: return
2016-06-29 15:47:52 +02:00
when (requestCode) {
REQUEST_SET_COLOR -> {
if (resultCode == Activity.RESULT_OK) {
if (data == null) return
val color = data.getIntExtra(EXTRA_COLOR, Color.TRANSPARENT)
2017-09-08 13:40:12 +02:00
userColorNameManager.setUserColor(user.key, color)
2016-06-29 15:47:52 +02:00
} else if (resultCode == ColorPickerDialogActivity.RESULT_CLEARED) {
2017-09-08 13:40:12 +02:00
userColorNameManager.clearUserColor(user.key)
2016-06-29 15:47:52 +02:00
}
}
REQUEST_ADD_TO_LIST -> {
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
2017-09-08 13:40:12 +02:00
twitter.addUserListMembersAsync(accountKey, list.id, user)
2016-06-29 15:47:52 +02:00
}
}
REQUEST_SELECT_ACCOUNT -> {
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return
2017-09-08 13:40:12 +02:00
val selectedAccountKey: UserKey = data.getParcelableExtra(EXTRA_ACCOUNT_KEY) ?: return
2017-04-25 17:54:18 +02:00
var userKey = user.key
2017-09-08 13:40:12 +02:00
if (account?.type == AccountType.MASTODON && account?.key?.host != selectedAccountKey.host) {
2017-04-26 17:38:59 +02:00
userKey = AcctPlaceholderUserKey(user.key.host)
2017-04-25 17:54:18 +02:00
}
2020-01-26 08:35:15 +01:00
activity?.let {
IntentUtils.openUserProfile(it, selectedAccountKey, userKey, user.screen_name,
user.extras?.statusnet_profile_url, preferences[newDocumentApiKey],
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
2017-04-17 15:10:14 +02:00
nameFirst = preferences[nameFirstKey]
2020-01-26 08:35:15 +01:00
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
2020-01-26 08:35:15 +01:00
val accountKey = args?.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY) ?: run {
2020-05-31 08:44:38 +02:00
activity.finish()
2017-04-12 14:58:08 +02:00
return
}
val userKey = args.getParcelable<UserKey?>(EXTRA_USER_KEY)
val screenName = 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))))
})
2017-06-26 08:48:05 +02:00
userFragmentView.windowInsetsListener = OnApplyWindowInsetsListener listener@ { _, insets ->
2017-09-01 12:17:01 +02:00
insets.getSystemWindowInsets(systemWindowsInsets)
2017-06-26 08:48:05 +02:00
val top = insets.systemWindowInsetTop
profileContentContainer.setPadding(0, top, 0, 0)
profileBannerSpace.statusBarHeight = top
2016-06-29 15:47:52 +02:00
if (profileBannerSpace.toolbarHeight == 0) {
var toolbarHeight = toolbar.measuredHeight
if (toolbarHeight == 0) {
toolbarHeight = ThemeUtils.getActionBarHeight(requireContext())
2016-06-29 15:47:52 +02:00
}
profileBannerSpace.toolbarHeight = toolbarHeight
}
2017-09-01 12:17:01 +02:00
updateRefreshProgressOffset()
2017-06-26 08:48:05 +02:00
return@listener insets
2016-06-29 15:47:52 +02:00
}
2017-06-11 15:49:05 +02:00
profileContentContainer.onSizeChangedListener = object : OnSizeChangedListener {
override fun onSizeChanged(view: View, w: Int, h: Int, oldw: Int, oldh: Int) {
val toolbarHeight = toolbar.measuredHeight
userProfileDrawer.setPadding(0, toolbarHeight, 0, 0)
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)
2017-06-11 15:49:05 +02:00
profileBanner.onSizeChangedListener = this
2016-07-02 06:05:23 +02:00
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()
2017-04-12 14:58:08 +02:00
getUserInfo(accountKey, userKey, screenName, false)
2016-06-29 15:47:52 +02:00
}
override fun onStart() {
super.onStart()
bus.register(this)
2017-04-14 17:03:58 +02:00
userColorNameManager.registerColorChangedListener(this)
userColorNameManager.registerNicknameChangedListener(this)
2016-06-29 15:47:52 +02:00
}
2017-04-13 05:18:12 +02:00
2016-06-29 15:47:52 +02:00
override fun onStop() {
2017-04-14 17:03:58 +02:00
userColorNameManager.unregisterColorChangedListener(this)
userColorNameManager.unregisterNicknameChangedListener(this)
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
2017-09-08 13:40:12 +02:00
val accountKey = user.account_key ?: return
2016-11-26 09:13:00 +01:00
val account = this.account
val relationship = this.relationship
val linkAvailable = LinkCreator.hasWebLink(user)
2017-09-08 13:40:12 +02:00
val isMyself = accountKey.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)
}
menu.setItemAvailability(R.id.qr_code, linkAvailable)
menu.setItemAvailability(R.id.copy_url, linkAvailable)
menu.setItemAvailability(R.id.open_in_browser, linkAvailable)
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.mention, !isMyself)
menu.setItemAvailability(R.id.incoming_friendships, isMyself)
menu.setItemAvailability(R.id.saved_searches, isMyself)
2016-07-04 03:31:17 +02:00
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.blocked_users, isMyself)
menu.setItemAvailability(R.id.block, !isMyself)
2016-11-26 09:13:00 +01:00
menu.setItemAvailability(R.id.add_to_home_screen_submenu,
ShortcutManagerCompat.isRequestPinShortcutSupported(requireContext()))
2017-04-22 09:27:05 +02:00
var canAddToList = false
var canMute = false
var canReportSpam = false
var canEnableRetweet = false
var canEnableNotifications = false
when (account?.type) {
AccountType.TWITTER -> {
canAddToList = true
canMute = true
canReportSpam = true
canEnableRetweet = true
canEnableNotifications = true
}
AccountType.MASTODON -> {
canMute = true
}
2016-06-29 15:47:52 +02:00
}
2017-04-22 09:27:05 +02:00
menu.setItemAvailability(R.id.add_to_list, canAddToList)
menu.setItemAvailability(R.id.mute_user, !isMyself && canMute)
menu.setItemAvailability(R.id.muted_users, isMyself && canMute)
menu.setItemAvailability(R.id.report_spam, !isMyself && canReportSpam)
menu.setItemAvailability(R.id.enable_retweets, !isMyself && canEnableRetweet)
2016-11-26 09:13:00 +01:00
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) {
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.send_direct_message, false)
menu.setItemAvailability(R.id.enable_notifications, false)
2016-06-29 15:47:52 +02:00
} else {
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.send_direct_message, relationship.can_dm)
menu.setItemAvailability(R.id.block, true)
2017-04-22 09:27:05 +02:00
menu.setItemAvailability(R.id.enable_notifications, canEnableNotifications &&
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 {
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.send_direct_message, false)
menu.setItemAvailability(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)
2020-01-26 08:35:15 +01:00
activity?.let { MenuUtils.addIntentToMenu(it, menu, intent, MENU_GROUP_USER_EXTENSION) }
2016-06-29 15:47:52 +02:00
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 {
2020-01-26 08:35:15 +01:00
val context = context ?: return false
2016-06-29 15:47:52 +02:00
val twitter = twitterWrapper
2017-09-08 13:40:12 +02:00
val user = user ?: return false
val accountKey = user.account_key ?: return false
2020-01-26 08:35:15 +01:00
val currentFragmentManager = fragmentManager ?: return false
2016-08-20 04:30:54 +02:00
val userRelationship = relationship
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) {
2017-09-08 13:40:12 +02:00
twitter.destroyBlockAsync(accountKey, user.key)
2016-06-29 15:47:52 +02:00
} else {
2020-01-26 08:35:15 +01:00
CreateUserBlockDialogFragment.show(currentFragmentManager, user)
2016-06-29 15:47:52 +02:00
}
}
R.id.report_spam -> {
2020-01-26 08:35:15 +01:00
ReportUserSpamDialogFragment.show(currentFragmentManager, user)
2016-06-29 15:47:52 +02:00
}
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-04-20 14:04:37 +02:00
Toast.makeText(activity, R.string.message_toast_user_filters_removed,
Toast.LENGTH_SHORT).show()
2016-12-11 07:29:00 +01:00
getFriendship()
2016-06-29 15:47:52 +02:00
} else {
2020-01-26 08:35:15 +01:00
AddUserFilterDialogFragment.show(currentFragmentManager, user)
2016-06-29 15:47:52 +02:00
}
}
R.id.mute_user -> {
if (userRelationship == null) return true
if (userRelationship.muting) {
2017-09-08 13:40:12 +02:00
twitter.destroyMuteAsync(accountKey, user.key)
2016-06-29 15:47:52 +02:00
} else {
2020-01-26 08:35:15 +01:00
CreateUserMuteDialogFragment.show(currentFragmentManager, user)
2016-06-29 15:47:52 +02:00
}
}
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 -> {
2017-04-09 08:15:01 +02:00
val am = AccountManager.get(activity)
val builder = Uri.Builder().apply {
scheme(SCHEME_TWIDERE)
authority(AUTHORITY_MESSAGES)
path(PATH_MESSAGES_CONVERSATION_NEW)
2017-09-08 13:40:12 +02:00
appendQueryParameter(QUERY_PARAM_ACCOUNT_KEY, accountKey.toString())
2017-04-09 08:15:01 +02:00
}
2016-06-29 15:47:52 +02:00
val intent = Intent(Intent.ACTION_VIEW, builder.build())
2017-09-08 13:40:12 +02:00
intent.putExtra(EXTRA_ACCOUNT, AccountUtils.getAccountDetails(am, accountKey,
2017-04-09 08:15:01 +02:00
true))
intent.putExtra(EXTRA_USERS, arrayOf(user))
intent.putExtra(EXTRA_OPEN_CONVERSATION, true)
2016-06-29 15:47:52 +02:00
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)
2020-01-26 08:35:15 +01:00
SetUserNicknameDialogFragment.show(currentFragmentManager, user.key, nick)
2016-06-29 15:47:52 +02:00
}
R.id.add_to_list -> {
2017-04-20 14:04:37 +02:00
showAddToListDialog(user)
2016-06-29 15:47:52 +02:00
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
2020-01-26 08:35:15 +01:00
activity?.let { intent.setClass(it, AccountSelectorActivity::class.java) }
2016-06-29 15:47:52 +02:00
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
2017-04-25 17:54:18 +02:00
when (account?.type) {
AccountType.MASTODON -> intent.putExtra(EXTRA_ACCOUNT_TYPE, AccountType.MASTODON)
else -> intent.putExtra(EXTRA_ACCOUNT_HOST, user.key.host)
}
2016-06-29 15:47:52 +02:00
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
}
R.id.follow -> {
if (userRelationship == null) return true
2017-09-08 13:40:12 +02:00
val updatingRelationship = twitter.isUpdatingRelationship(accountKey,
2016-06-29 15:47:52 +02:00
user.key)
if (!updatingRelationship) {
if (userRelationship.following) {
2020-01-26 08:35:15 +01:00
DestroyFriendshipDialogFragment.show(currentFragmentManager, user)
2016-06-29 15:47:52 +02:00
} else {
2017-09-08 13:40:12 +02:00
twitter.createFriendshipAsync(accountKey, user.key, user.screen_name)
2016-06-29 15:47:52 +02:00
}
}
return true
}
R.id.enable_retweets -> {
val newState = !item.isChecked
val update = FriendshipUpdate()
update.retweets(newState)
2017-09-08 13:40:12 +02:00
twitter.updateFriendship(accountKey, user.key, update)
2016-06-29 15:47:52 +02:00
item.isChecked = newState
return true
}
R.id.enable_notifications -> {
val newState = !item.isChecked
val update = FriendshipUpdate()
update.deviceNotifications(newState)
2017-09-08 13:40:12 +02:00
twitter.updateFriendship(accountKey, user.key, update)
item.isChecked = newState
return true
}
2016-06-29 15:47:52 +02:00
R.id.muted_users -> {
2020-01-26 08:35:15 +01:00
activity?.let { IntentUtils.openMutesUsers(it, accountKey) }
2016-06-29 15:47:52 +02:00
return true
}
R.id.blocked_users -> {
2017-09-08 13:40:12 +02:00
IntentUtils.openUserBlocks(activity, accountKey)
2016-06-29 15:47:52 +02:00
return true
}
R.id.incoming_friendships -> {
2020-01-26 08:35:15 +01:00
activity?.let { IntentUtils.openIncomingFriendships(it, accountKey) }
2016-06-29 15:47:52 +02:00
return true
}
R.id.user_mentions -> {
2017-09-08 13:40:12 +02:00
IntentUtils.openUserMentions(context, accountKey, user.screen_name)
2016-06-29 15:47:52 +02:00
return true
}
R.id.saved_searches -> {
2017-09-08 13:40:12 +02:00
IntentUtils.openSavedSearches(context, accountKey)
2016-06-29 15:47:52 +02:00
return true
}
R.id.open_in_browser -> {
val uri = LinkCreator.getUserWebLink(user) ?: return true
2016-06-29 15:47:52 +02:00
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
}
2020-04-22 16:23:57 +02:00
R.id.copy_url -> {
val uri = LinkCreator.getUserWebLink(user)
ClipboardUtils.setText(context, uri.toString())
Toast.makeText(context, R.string.message_toast_link_copied_to_clipboard, Toast.LENGTH_SHORT).show()
return true
}
2017-04-03 16:55:41 +02:00
R.id.qr_code -> {
executeAfterFragmentResumed {
2017-04-10 08:13:33 +02:00
val df = UserQrDialogFragment()
2017-04-03 16:55:41 +02:00
df.arguments = Bundle {
this[EXTRA_USER] = user
}
df.show(it.childFragmentManager, "user_qr_code")
}
2016-06-29 15:47:52 +02:00
return true
}
R.id.add_user_to_home_screen -> {
ShortcutCreator.performCreation(this) {
2017-09-08 13:40:12 +02:00
ShortcutCreator.user(context, accountKey, user)
}
}
R.id.add_statuses_to_home_screen -> {
ShortcutCreator.performCreation(this) {
2017-09-08 13:40:12 +02:00
ShortcutCreator.userTimeline(context, accountKey, user)
}
}
R.id.add_favorites_to_home_screen -> {
ShortcutCreator.performCreation(this) {
2017-09-08 13:40:12 +02:00
ShortcutCreator.userFavorites(context, accountKey, user)
}
}
R.id.add_media_to_home_screen -> {
ShortcutCreator.performCreation(this) {
2017-09-08 13:40:12 +02:00
ShortcutCreator.userMediaTimeline(context, accountKey, user)
}
}
2016-06-29 15:47:52 +02:00
else -> {
val intent = item.intent
if (intent?.resolveActivity(context.packageManager) != null) {
2016-06-29 15:47:52 +02:00
startActivity(intent)
}
}
}
return true
}
2017-04-20 14:04:37 +02:00
2016-06-29 15:47:52 +02:00
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)
}
2017-04-13 05:18:12 +02:00
private fun updateSubtitle() {
val activity = activity as AppCompatActivity
val actionBar = activity.supportActionBar ?: return
val user = this.user
if (user == null) {
actionBar.subtitle = null
return
}
val spec = pagerAdapter.get(viewPager.currentItem)
2020-05-31 08:11:38 +02:00
if (BuildConfig.DEBUG && spec.type == null) { error("Assertion failed") }
2017-04-13 05:18:12 +02:00
when (spec.type) {
TAB_TYPE_STATUSES, TAB_TYPE_STATUSES_WITH_REPLIES -> {
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 (user.favorites_count < 0) {
if (preferences[iWantMyStarsBackKey]) {
actionBar.setSubtitle(R.string.title_favorites)
} else {
actionBar.setSubtitle(R.string.title_likes)
}
} else if (preferences[iWantMyStarsBackKey]) {
2017-04-13 05:18:12 +02:00
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()
}
2016-06-29 15:47:52 +02:00
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
2017-06-25 17:01:33 +02:00
override fun onApplySystemWindowInsets(insets: Rect) {
2016-06-29 15:47:52 +02:00
}
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) {
2017-09-08 13:40:12 +02:00
val activity = activity ?: return
2020-01-26 08:35:15 +01:00
val fragmentManager = fragmentManager ?: return
2017-09-08 13:40:12 +02:00
val user = user ?: return
val accountKey = user.account_key ?: return
2016-06-29 15:47:52 +02:00
when (view.id) {
R.id.errorContainer -> {
getUserInfo(true)
}
R.id.follow -> {
2017-09-08 13:40:12 +02:00
if (accountKey.maybeEquals(user.key)) {
2020-01-26 08:35:15 +01:00
IntentUtils.openProfileEditor(activity, accountKey)
2016-06-29 15:47:52 +02:00
} 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
2020-06-09 02:21:48 +02:00
when {
userRelationship.blocking -> {
twitter.destroyBlockAsync(accountKey, user.key)
}
userRelationship.blocked_by -> {
CreateUserBlockDialogFragment.show(childFragmentManager, user)
}
userRelationship.following -> {
DestroyFriendshipDialogFragment.show(fragmentManager, user)
}
else -> {
twitter.createFriendshipAsync(accountKey, user.key, user.screen_name)
}
2016-06-29 15:47:52 +02:00
}
}
}
2016-07-02 06:05:23 +02:00
R.id.profileImage -> {
2017-04-10 13:11:49 +02:00
val url = user.originalProfileImage ?: return
2016-06-29 15:47:52 +02:00
val profileImage = ParcelableMediaUtils.image(url)
profileImage.type = ParcelableMedia.Type.IMAGE
2017-04-12 08:12:45 +02:00
profileImage.preview_url = user.profile_image_url
2016-06-29 15:47:52 +02:00
val media = arrayOf(profileImage)
2017-09-08 13:40:12 +02:00
IntentUtils.openMedia(activity, accountKey, media, null, false,
2017-01-20 15:08:42 +01:00
preferences[newDocumentApiKey], preferences[displaySensitiveContentsKey])
2016-06-29 15:47:52 +02:00
}
R.id.profileBanner -> {
2017-04-16 15:09:56 +02:00
val url = user.getBestProfileBanner(0) ?: return
2016-06-29 15:47:52 +02:00
val profileBanner = ParcelableMediaUtils.image(url)
profileBanner.type = ParcelableMedia.Type.IMAGE
val media = arrayOf(profileBanner)
2017-09-08 13:40:12 +02:00
IntentUtils.openMedia(activity, accountKey, media, null, false,
2017-01-20 15:08:42 +01:00
preferences[newDocumentApiKey], preferences[displaySensitiveContentsKey])
2016-06-29 15:47:52 +02:00
}
R.id.listedContainer -> {
2020-01-26 08:35:15 +01:00
IntentUtils.openUserLists(activity, accountKey, user.key,
2016-06-29 15:47:52 +02:00
user.screen_name)
}
R.id.groupsContainer -> {
2020-01-26 08:35:15 +01:00
IntentUtils.openUserGroups(activity, accountKey, user.key,
2016-06-29 15:47:52 +02:00
user.screen_name)
}
R.id.followersContainer -> {
2020-01-26 08:35:15 +01:00
IntentUtils.openUserFollowers(activity, accountKey, user.key,
2016-06-29 15:47:52 +02:00
user.screen_name)
}
R.id.friendsContainer -> {
2020-01-26 08:35:15 +01:00
IntentUtils.openUserFriends(activity, accountKey, user.key,
2016-06-29 15:47:52 +02:00
user.screen_name)
}
2016-07-02 06:05:23 +02:00
R.id.nameContainer -> {
2017-09-08 13:40:12 +02:00
if (accountKey == user.key) return
2020-01-26 08:35:15 +01:00
IntentUtils.openProfileEditor(activity, accountKey)
2016-06-29 15:47:52 +02:00
}
2017-04-05 07:12:01 +02:00
R.id.urlContainer -> {
val uri = user.urlPreferred?.let(Uri::parse) ?: return
2020-01-26 08:35:15 +01:00
OnLinkClickHandler.openLink(activity, preferences, uri)
2017-04-05 07:12:01 +02:00
}
2016-06-29 15:47:52 +02:00
R.id.profileBirthdayBanner -> {
2016-12-11 07:29:00 +01:00
hideBirthdayView = true
2020-01-26 08:35:15 +01:00
profileBirthdayBanner.startAnimation(AnimationUtils.loadAnimation(activity, android.R.anim.fade_out))
2016-07-02 06:05:23 +02:00
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
2020-01-26 08:35:15 +01:00
val activity = activity ?: return false
2016-06-29 15:47:52 +02:00
when (type) {
TwidereLinkify.LINK_TYPE_MENTION -> {
2017-04-07 13:05:02 +02:00
IntentUtils.openUserProfile(activity, user.account_key, null, link, null,
2017-08-28 06:31:19 +02:00
preferences[newDocumentApiKey], null)
2016-06-29 15:47:52 +02:00
return true
}
TwidereLinkify.LINK_TYPE_HASHTAG -> {
2020-06-08 23:07:20 +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
2020-06-08 23:19:10 +02:00
intent = if (uri.scheme != null) {
Intent(Intent.ACTION_VIEW, uri)
2016-06-29 15:47:52 +02:00
} else {
2020-06-08 23:19:10 +02:00
Intent(Intent.ACTION_VIEW, uri.buildUpon().scheme("http").build())
2016-06-29 15:47:52 +02:00
}
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
}
2017-04-14 16:34:43 +02:00
override fun onUserNicknameChanged(userKey: UserKey, nick: String?) {
2017-04-12 14:58:08 +02:00
if (user?.key != userKey) return
displayUser(user, account)
2016-06-29 15:47:52 +02:00
}
2017-04-12 14:58:08 +02:00
override fun onUserColorChanged(userKey: UserKey, color: Int) {
if (user?.key != userKey) 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) {
requestApplyInsets()
2016-06-29 15:47:52 +02:00
}
}
2017-08-28 06:31:19 +02:00
@SuppressLint("ClickableViewAccessibility")
2016-06-29 15:47:52 +02:00
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
}
2017-09-01 12:17:01 +02:00
private fun updateRefreshProgressOffset() {
val insets = this.systemWindowsInsets
if (insets.top == 0 || userProfileSwipeLayout == null || userProfileSwipeLayout.isRefreshing) {
return
}
val progressCircleDiameter = userProfileSwipeLayout.progressCircleDiameter
if (progressCircleDiameter == 0) return
val progressViewStart = 0 - progressCircleDiameter
val progressViewEnd = profileBannerSpace.toolbarHeight + resources.getDimensionPixelSize(R.dimen.element_spacing_normal)
userProfileSwipeLayout.setProgressViewOffset(false, progressViewStart, progressViewEnd)
}
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)
2017-09-01 12:17:01 +02:00
if (!friendShipLoaderInitialized) {
lm.initLoader(LOADER_ID_FRIENDSHIP, args, friendshipLoaderCallbacks)
2017-09-01 12:17:01 +02:00
friendShipLoaderInitialized = 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
2017-09-08 13:40:12 +02:00
val accountKey = user.account_key ?: return
getUserInfo(accountKey, user.key, user.screen_name, omitIntentExtra)
2016-06-29 15:47:52 +02:00
}
private fun setUiColor(color: Int) {
2020-01-26 08:35:15 +01:00
val activity = activity as? BaseActivity ?: return
2017-04-20 07:28:57 +02:00
val theme = Chameleon.getOverrideTheme(activity, activity)
uiColor = if (color != 0) color else theme.colorPrimary
2016-12-11 07:29:00 +01:00
previousActionBarItemIsDark = 0
previousTabItemIsDark = 0
2017-03-04 05:26:14 +01:00
setupBaseActionBar()
2020-06-08 23:19:10 +02:00
primaryColor = if (theme.isToolbarColored) {
color
2016-06-29 15:47:52 +02:00
} else {
2020-06-08 23:19:10 +02:00
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
2020-06-08 23:19:10 +02:00
taskColor = if (theme.isToolbarColored) {
ColorUtils.setAlphaComponent(color, 0xFF)
2016-06-29 15:47:52 +02:00
} else {
2020-06-08 23:19:10 +02:00
ColorUtils.setAlphaComponent(theme.colorToolbar, 0xFF)
2016-06-29 15:47:52 +02:00
}
2017-04-14 17:03:58 +02:00
val user = this.user
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)) {
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() {
2020-01-26 08:35:15 +01:00
val args = arguments ?: return
2016-06-29 15:47:52 +02:00
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-04-12 14:58:08 +02:00
userKey = args.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
2017-03-27 15:56:03 +02:00
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
this[UserTimelineFragment.EXTRA_LOAD_PINNED_STATUS] = 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)
2017-04-19 13:30:07 +02:00
if (account?.type != AccountType.MASTODON || account?.key == userKey) {
if (preferences[iWantMyStarsBackKey]) {
pagerAdapter.add(cls = UserFavoritesFragment::class.java, args = tabArgs,
name = getString(R.string.title_favorites), type = TAB_TYPE_FAVORITES,
position = TAB_POSITION_FAVORITES)
} else {
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(),
2017-04-15 10:42:50 +02:00
ChameleonUtils.darkenColor(primaryColorDark)) as Int
2016-06-29 15:47:52 +02:00
val window = activity.window
2017-09-13 11:52:09 +02:00
userFragmentView.statusBarColor = statusBarColor
WindowSupport.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
2020-06-08 23:19:10 +02:00
tabOutlineAlphaFactor = if (offset - spaceHeight > 0) {
1f - ((offset - spaceHeight) / profileContentHeight).coerceIn(0f, 1f)
2016-06-29 15:47:52 +02:00
} else {
2020-06-08 23:19:10 +02:00
1f
2016-06-29 15:47:52 +02:00
}
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
}
2017-04-25 17:54:18 +02:00
return user_key.id == user.extras?.unique_id || user_key.id == user.key.id
2017-04-07 09:21:56 +02:00
}
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) {
val followButton = followContainer.follow
followButton.setImageResource(icon)
ViewCompat.setBackgroundTintMode(followButton, PorterDuff.Mode.SRC_ATOP)
2020-01-26 08:35:15 +01:00
ViewCompat.setBackgroundTintList(followButton, context?.let { ContextCompat.getColorStateList(it, color) })
followButton.contentDescription = getString(label)
2017-04-07 09:21:56 +02:00
}
2016-06-29 15:47:52 +02:00
2017-04-20 14:04:37 +02:00
private fun showAddToListDialog(user: ParcelableUser) {
2017-09-08 13:40:12 +02:00
val accountKey = user.account_key ?: return
2017-04-20 14:04:37 +02:00
val weakThis = WeakReference(this)
executeAfterFragmentResumed {
ProgressDialogFragment.show(it.childFragmentManager, "get_list_progress")
}.then {
val fragment = weakThis.get() ?: throw InterruptedException()
fun MicroBlog.getUserListOwnerMemberships(id: String): ArrayList<UserList> {
val result = ArrayList<UserList>()
var nextCursor: Long
val paging = Paging()
paging.count(100)
do {
val resp = getUserListMemberships(id, paging, true)
result.addAll(resp)
nextCursor = resp.nextCursor
paging.cursor(nextCursor)
} while (nextCursor > 0)
return result
}
val microBlog = MicroBlogAPIFactory.getInstance(fragment.requireContext(), accountKey)
2017-04-20 14:04:37 +02:00
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 ->
2017-09-08 13:40:12 +02:00
val userList = item.toParcelable(accountKey)
2017-04-20 14:04:37 +02:00
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()
}.alwaysUi {
val fragment = weakThis.get() ?: return@alwaysUi
fragment.executeAfterFragmentResumed {
it.childFragmentManager.dismissDialogFragment("get_list_progress")
}
}.successUi { result ->
val fragment = weakThis.get() ?: return@successUi
2017-08-31 19:06:58 +02:00
fragment.executeAfterFragmentResumed { f ->
2017-04-20 14:04:37 +02:00
val df = AddRemoveUserListDialogFragment()
df.arguments = Bundle {
2017-09-08 13:40:12 +02:00
this[EXTRA_ACCOUNT_KEY] = accountKey
2017-04-20 14:04:37 +02:00
this[EXTRA_USER_KEY] = user.key
this[EXTRA_USER_LISTS] = result
}
2017-08-31 19:06:58 +02:00
df.show(f.childFragmentManager, "add_remove_list")
2017-04-20 14:04:37 +02:00
}
}.failUi {
val fragment = weakThis.get() ?: return@failUi
Toast.makeText(fragment.context, it.getErrorMessage(fragment.requireContext()),
2017-04-20 14:04:37 +02:00
Toast.LENGTH_SHORT).show()
}
}
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() {
2020-06-09 00:50:51 +02:00
val shadowAlpha = (alpha * (1 - factor).coerceIn(0f, 1f)).roundToInt()
2016-12-11 07:29:00 +01:00
shadowDrawable.alpha = shadowAlpha
2016-06-29 15:47:52 +02:00
val hasColor = color != 0
2020-06-09 00:50:51 +02:00
val colorAlpha = if (hasColor) (alpha * factor.coerceIn(0f, 1f)).roundToInt() 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) {
2017-04-22 09:18:44 +02:00
return SingleResponse(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) {
2017-06-20 07:18:46 +02:00
return SingleResponse(ParcelableRelationship().apply {
account_key = accountKey
user_key = userKey
filtering = isFiltering
})
2016-06-29 15:47:52 +02:00
}
2016-12-04 06:45:57 +01:00
val details = AccountUtils.getAccountDetails(AccountManager.get(context),
2017-04-22 09:18:44 +02:00
accountKey, true) ?: return SingleResponse(MicroBlogException("No Account"))
2016-12-04 06:45:57 +01:00
if (details.type == AccountType.TWITTER) {
2017-05-03 15:42:05 +02:00
if (!accountKey.hasSameHost(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
}
}
try {
2017-04-22 09:18:44 +02:00
val data = when (details.type) {
AccountType.MASTODON -> {
val mastodon = details.newMicroBlogInstance(context, Mastodon::class.java)
mastodon.getRelationships(arrayOf(userKey.id))?.firstOrNull()
?.toParcelable(accountKey, userKey, isFiltering)
?: throw MicroBlogException("No relationship")
}
else -> {
val microBlog = details.newMicroBlogInstance(context, MicroBlog::class.java)
microBlog.showFriendship(user.key.id).toParcelable(accountKey, userKey,
isFiltering)
}
}
if (data.blocking || data.blocked_by) {
2016-06-29 15:47:52 +02:00
Utils.setLastSeen(context, userKey, -1)
} else {
Utils.setLastSeen(context, userKey, System.currentTimeMillis())
}
2016-11-26 10:41:35 +01:00
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)
2017-04-22 09:18:44 +02:00
return SingleResponse(data)
2016-06-29 15:47:52 +02:00
} catch (e: MicroBlogException) {
2017-04-22 09:18:44 +02:00
return SingleResponse(e)
2016-06-29 15:47:52 +02:00
}
}
override fun onStartLoading() {
forceLoad()
}
}
2016-08-30 14:23:59 +02:00
class AddRemoveUserListDialogFragment : BaseDialogFragment() {
2017-04-12 14:58:08 +02:00
2016-08-30 14:23:59 +02:00
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val lists = requireArguments().getTypedArray<ParcelableUserList>(EXTRA_USER_LISTS)
val userKey = requireArguments().getParcelable<UserKey>(EXTRA_USER_KEY)!!
val accountKey = requireArguments().getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)!!
val builder = AlertDialog.Builder(requireContext())
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-08-31 19:06:58 +02:00
dialog.onShow { d ->
d.applyTheme()
d.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val checkedPositions = d.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(e, successfulStates)
2016-08-30 14:23:59 +02:00
}
}.alwaysUi {
2017-03-01 02:11:56 +01:00
val activity = weakActivity.get() as? IBaseActivity<*> ?: return@alwaysUi
2017-08-31 19:06:58 +02:00
activity.executeAfterFragmentResumed { a ->
val manager = a.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)
2017-08-31 19:06:58 +02:00
d.listView.setItemChecked(pos, checked)
2016-08-30 14:23:59 +02:00
states[pos] = checked
}
}
Toast.makeText(context, e.getErrorMessage(requireContext()), Toast.LENGTH_SHORT).show()
2016-08-30 14:23:59 +02:00
}
}
2017-08-31 19:06:58 +02:00
d.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
2016-08-30 14:23:59 +02:00
val df = CreateUserListDialogFragment()
df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey
}
df.show(requireFragmentManager(), "create_user_list")
2016-08-30 14:23:59 +02:00
}
}
return dialog
}
class UpdateListsException(cause: Throwable, val successfulStates: SparseBooleanArray) : MicroBlogException(cause)
2016-08-30 14:23:59 +02:00
}
2016-06-29 15:47:52 +02:00
companion object {
private val sArgbEvaluator = ArgbEvaluator()
2020-06-08 23:11:06 +02:00
private const val LOADER_ID_USER = 1
private const val LOADER_ID_FRIENDSHIP = 2
2016-06-29 15:47:52 +02:00
private const val TAB_POSITION_STATUSES = 0
private const val TAB_POSITION_MEDIA = 1
private const val TAB_POSITION_FAVORITES = 2
private const val TAB_TYPE_STATUSES = "statuses"
private const val TAB_TYPE_STATUSES_WITH_REPLIES = "statuses_with_replies"
private const val TAB_TYPE_MEDIA = "media"
private const val TAB_TYPE_FAVORITES = "favorites"
2017-10-02 15:22:26 +02:00
private val ParcelableUser.hide_protected_contents: Boolean
get() = user_type != AccountType.MASTODON && is_protected
2016-06-29 15:47:52 +02:00
}
}