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

421 lines
17 KiB
Kotlin
Raw Normal View History

2016-07-02 05:54:53 +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
import android.app.Activity
import android.app.Dialog
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.os.Bundle
import androidx.loader.app.LoaderManager
2020-01-26 08:35:15 +01:00
import androidx.loader.app.LoaderManager.LoaderCallbacks
import androidx.loader.content.FixedAsyncTaskLoader
import androidx.loader.content.Loader
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.appcompat.app.AlertDialog
2016-07-02 05:54:53 +02:00
import android.text.TextUtils
import android.util.Log
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.View.OnClickListener
import com.squareup.otto.Subscribe
2017-04-07 13:05:02 +02:00
import org.mariotaku.kpreferences.get
2017-04-12 10:17:20 +02:00
import org.mariotaku.ktextension.setItemAvailability
2016-07-02 05:54:53 +02:00
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.UserList
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.AccountSelectorActivity
2017-01-29 14:34:22 +01:00
import org.mariotaku.twidere.activity.UserSelectorActivity
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.adapter.SupportTabsAdapter
2017-04-21 11:23:55 +02:00
import org.mariotaku.twidere.app.TwidereApplication
2017-04-07 13:05:02 +02:00
import org.mariotaku.twidere.constant.newDocumentApiKey
2017-02-05 14:42:20 +01:00
import org.mariotaku.twidere.extension.applyTheme
2017-04-21 12:01:54 +02:00
import org.mariotaku.twidere.extension.model.api.microblog.toParcelable
import org.mariotaku.twidere.extension.neutral
2017-06-19 15:45:41 +02:00
import org.mariotaku.twidere.extension.onShow
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowInsetsCallback
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
2017-04-21 14:24:15 +02:00
import org.mariotaku.twidere.fragment.statuses.UserListTimelineFragment
2017-04-21 11:23:55 +02:00
import org.mariotaku.twidere.fragment.users.UserListMembersFragment
import org.mariotaku.twidere.fragment.users.UserListSubscribersFragment
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.model.ParcelableUser
import org.mariotaku.twidere.model.ParcelableUserList
import org.mariotaku.twidere.model.SingleResponse
import org.mariotaku.twidere.model.UserKey
2017-02-09 09:00:12 +01:00
import org.mariotaku.twidere.model.event.UserListSubscriptionEvent
import org.mariotaku.twidere.model.event.UserListUpdatedEvent
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.util.*
2017-09-03 16:53:27 +02:00
import org.mariotaku.twidere.util.shortcut.ShortcutCreator
2016-07-02 05:54:53 +02:00
2017-03-20 14:46:18 +01:00
class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
LoaderCallbacks<SingleResponse<ParcelableUserList>>, SystemWindowInsetsCallback,
2017-03-20 14:46:18 +01:00
SupportFragmentCallback {
2016-07-02 05:54:53 +02:00
2016-07-08 07:24:39 +02:00
private var userListLoaderInitialized: Boolean = false
2016-07-02 05:54:53 +02:00
var userList: ParcelableUserList? = null
private set
fun displayUserList(userList: ParcelableUserList?) {
val activity = activity ?: return
LoaderManager.getInstance(this).destroyLoader(0)
2016-07-02 05:54:53 +02:00
this.userList = userList
if (userList != null) {
activity.title = userList.name
} else {
2017-04-17 15:10:14 +02:00
activity.setTitle(R.string.title_user_list)
2016-07-02 05:54:53 +02:00
}
2016-11-30 08:18:43 +01:00
activity.invalidateOptionsMenu()
2016-07-02 05:54:53 +02:00
}
fun getUserListInfo(omitIntentExtra: Boolean) {
val lm = LoaderManager.getInstance(this)
2016-07-02 05:54:53 +02:00
lm.destroyLoader(0)
val args = Bundle(arguments)
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
2016-07-08 07:24:39 +02:00
if (!userListLoaderInitialized) {
2016-07-02 05:54:53 +02:00
lm.initLoader(0, args, this)
2016-07-08 07:24:39 +02:00
userListLoaderInitialized = true
2016-07-02 05:54:53 +02:00
} else {
lm.restartLoader(0, args, this)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
val twitter = twitterWrapper
when (requestCode) {
REQUEST_SELECT_USER -> {
val userList = this.userList
2016-07-08 07:24:39 +02:00
if (resultCode != Activity.RESULT_OK || !data!!.hasExtra(EXTRA_USER) || userList == null)
2016-07-02 05:54:53 +02:00
return
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) ?: return
2016-07-02 05:54:53 +02:00
twitter.addUserListMembersAsync(userList.account_key, userList.id, user)
return
}
REQUEST_SELECT_ACCOUNT -> {
if (resultCode == Activity.RESULT_OK) {
if (data == null || !data.hasExtra(EXTRA_ID)) return
val userList = this.userList
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
2020-01-26 08:35:15 +01:00
activity?.let {
IntentUtils.openUserListDetails(it, accountKey, userList!!.id,
userList.user_key, userList.user_screen_name, userList.name)
}
2016-07-02 05:54:53 +02:00
}
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val activity = activity
setHasOptionsMenu(true)
2020-01-26 08:35:15 +01:00
if (activity != null) {
Utils.setNdefPushMessageCallback(activity, CreateNdefMessageCallback {
val userList = userList ?: return@CreateNdefMessageCallback null
NdefMessage(arrayOf(NdefRecord.createUri(LinkCreator.getTwitterUserListLink(userList.user_screen_name, userList.name))))
})
}
2016-07-02 05:54:53 +02:00
getUserListInfo(false)
}
override fun addTabs(adapter: SupportTabsAdapter) {
2020-01-26 08:35:15 +01:00
val args = arguments ?: return
2016-07-02 05:54:53 +02:00
val tabArgs = Bundle()
if (args.containsKey(EXTRA_USER_LIST)) {
val userList = args.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)!!
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key)
tabArgs.putParcelable(EXTRA_USER_KEY, userList.user_key)
tabArgs.putString(EXTRA_SCREEN_NAME, userList.user_screen_name)
tabArgs.putString(EXTRA_LIST_ID, userList.id)
tabArgs.putString(EXTRA_LIST_NAME, userList.name)
} else {
tabArgs.putParcelable(EXTRA_ACCOUNT_KEY, args.getParcelable(EXTRA_ACCOUNT_KEY))
tabArgs.putParcelable(EXTRA_USER_KEY, args.getParcelable(EXTRA_USER_KEY))
tabArgs.putString(EXTRA_SCREEN_NAME, args.getString(EXTRA_SCREEN_NAME))
tabArgs.putString(EXTRA_LIST_ID, args.getString(EXTRA_LIST_ID))
tabArgs.putString(EXTRA_LIST_NAME, args.getString(EXTRA_LIST_NAME))
}
2017-03-27 05:08:09 +02:00
adapter.add(cls = UserListTimelineFragment::class.java, args = tabArgs, name = getString(R.string.title_statuses))
adapter.add(cls = UserListMembersFragment::class.java, args = tabArgs, name = getString(R.string.members))
2017-05-21 10:51:03 +02:00
adapter.add(cls = UserListSubscribersFragment::class.java, args = tabArgs, name = getString(R.string.title_userlist_subscribers))
2016-07-02 05:54:53 +02:00
}
override fun onStart() {
super.onStart()
bus.register(this)
}
override fun onStop() {
bus.unregister(this)
super.onStop()
}
override fun onDestroyView() {
userList = null
LoaderManager.getInstance(this).destroyLoader(0)
2016-07-02 05:54:53 +02:00
super.onDestroyView()
}
2017-04-12 10:17:20 +02:00
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_user_list, menu)
2016-07-02 05:54:53 +02:00
}
2017-04-12 10:17:20 +02:00
override fun onPrepareOptionsMenu(menu: Menu) {
2016-07-02 05:54:53 +02:00
val userList = this.userList
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.info, userList != null)
menu.removeGroup(MENU_GROUP_USER_LIST_EXTENSION)
2016-07-02 05:54:53 +02:00
if (userList != null) {
val isMyList = userList.user_key == userList.account_key
val isFollowing = userList.is_following
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.edit, isMyList)
menu.setItemAvailability(R.id.follow, !isMyList)
menu.setItemAvailability(R.id.add, isMyList)
menu.setItemAvailability(R.id.delete, isMyList)
2016-07-02 05:54:53 +02:00
val followItem = menu.findItem(R.id.follow)
if (isFollowing) {
followItem.setIcon(R.drawable.ic_action_cancel)
2017-01-26 14:28:43 +01:00
followItem.setTitle(R.string.action_unsubscribe)
2016-07-02 05:54:53 +02:00
} else {
followItem.setIcon(R.drawable.ic_action_add)
2017-01-26 14:28:43 +01:00
followItem.setTitle(R.string.action_subscribe)
2016-07-02 05:54:53 +02:00
}
val extensionsIntent = Intent(INTENT_ACTION_EXTENSION_OPEN_USER_LIST)
2017-04-21 11:23:55 +02:00
extensionsIntent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
2016-07-02 05:54:53 +02:00
extensionsIntent.putExtra(EXTRA_USER_LIST, userList)
2020-01-26 08:35:15 +01:00
activity?.let {
MenuUtils.addIntentToMenu(it, menu, extensionsIntent, MENU_GROUP_USER_LIST_EXTENSION)
menu.setItemAvailability(R.id.add_to_home_screen_submenu, ShortcutManagerCompat.isRequestPinShortcutSupported(it))
}
2016-07-02 05:54:53 +02:00
} else {
2017-04-12 10:17:20 +02:00
menu.setItemAvailability(R.id.edit, false)
menu.setItemAvailability(R.id.follow, false)
menu.setItemAvailability(R.id.add, false)
menu.setItemAvailability(R.id.delete, false)
2017-09-03 16:53:27 +02:00
menu.setItemAvailability(R.id.add_to_home_screen_submenu, false)
2016-07-02 05:54:53 +02:00
}
}
2017-04-12 10:17:20 +02:00
override fun onOptionsItemSelected(item: MenuItem): Boolean {
2016-07-02 05:54:53 +02:00
val twitter = twitterWrapper
val userList = userList ?: return false
2020-01-26 08:35:15 +01:00
val activity = activity ?: return false
val fragmentManager = parentFragmentManager
2017-04-12 10:17:20 +02:00
when (item.itemId) {
2016-07-02 05:54:53 +02:00
R.id.add -> {
if (userList.user_key != userList.account_key) return false
val intent = Intent(INTENT_ACTION_SELECT_USER)
2017-01-29 14:34:22 +01:00
intent.setClass(activity, UserSelectorActivity::class.java)
2016-07-02 05:54:53 +02:00
intent.putExtra(EXTRA_ACCOUNT_KEY, userList.account_key)
startActivityForResult(intent, REQUEST_SELECT_USER)
}
R.id.delete -> {
if (userList.user_key != userList.account_key) return false
DestroyUserListDialogFragment.show(fragmentManager, userList)
}
R.id.edit -> {
val args = Bundle()
args.putParcelable(EXTRA_ACCOUNT_KEY, userList.account_key)
args.putString(EXTRA_LIST_NAME, userList.name)
args.putString(EXTRA_DESCRIPTION, userList.description)
args.putBoolean(EXTRA_IS_PUBLIC, userList.is_public)
args.putString(EXTRA_LIST_ID, userList.id)
val f = EditUserListDialogFragment()
f.arguments = args
f.show(fragmentManager, "edit_user_list_details")
return true
}
R.id.follow -> {
if (userList.is_following) {
DestroyUserListSubscriptionDialogFragment.show(fragmentManager, userList)
} else {
twitter.createUserListSubscriptionAsync(userList.account_key, userList.id)
}
return true
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
intent.setClass(activity, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
}
2016-07-08 07:24:39 +02:00
R.id.info -> {
val df = UserListDetailsDialogFragment()
2020-01-26 08:35:15 +01:00
df.arguments = Bundle().apply {
putParcelable(EXTRA_USER_LIST, userList)
}
2016-07-08 07:24:39 +02:00
df.show(childFragmentManager, "user_list_details")
}
2017-09-03 16:53:27 +02:00
R.id.add_statuses_to_home_screen -> {
ShortcutCreator.performCreation(this) {
2020-01-26 08:35:15 +01:00
ShortcutCreator.userListTimeline(activity, userList.account_key, userList)
2017-09-03 16:53:27 +02:00
}
}
2016-07-02 05:54:53 +02:00
else -> {
if (item.intent != null) {
try {
startActivity(item.intent)
} catch (e: ActivityNotFoundException) {
Log.w(LOGTAG, e)
return false
}
}
}
}
return true
}
override fun onClick(view: View) {
when (view.id) {
R.id.errorContainer -> {
getUserListInfo(true)
}
2016-07-02 06:05:23 +02:00
R.id.profileImage -> {
2016-07-02 05:54:53 +02:00
val userList = this.userList ?: return
2020-01-26 08:35:15 +01:00
activity?.let {
IntentUtils.openUserProfile(it, userList.account_key, userList.user_key,
userList.user_screen_name, null, preferences[newDocumentApiKey], null)
}
2016-07-02 05:54:53 +02:00
}
}
}
2020-01-26 08:35:15 +01:00
override fun onCreateLoader(id: Int, args: Bundle?): Loader<SingleResponse<ParcelableUserList>> {
val accountKey = args!!.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
2017-04-12 14:58:08 +02:00
val userKey = args.getParcelable<UserKey?>(EXTRA_USER_KEY)
2016-07-02 05:54:53 +02:00
val listId = args.getString(EXTRA_LIST_ID)
val listName = args.getString(EXTRA_LIST_NAME)
val screenName = args.getString(EXTRA_SCREEN_NAME)
val omitIntentExtra = args.getBoolean(EXTRA_OMIT_INTENT_EXTRA, true)
return ParcelableUserListLoader(requireActivity(), omitIntentExtra, arguments, accountKey, listId,
2016-07-02 05:54:53 +02:00
listName, userKey, screenName)
}
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUserList>>,
2020-01-26 08:35:15 +01:00
data: SingleResponse<ParcelableUserList>?) {
2016-07-02 05:54:53 +02:00
if (data == null) return
if (activity == null) return
if (data.hasData()) {
val list = data.data
displayUserList(list)
} else if (data.hasException()) {
}
}
override fun onLoaderReset(loader: Loader<SingleResponse<ParcelableUserList>>) {
}
@Subscribe
fun onUserListUpdated(event: UserListUpdatedEvent) {
if (userList == null) return
if (TextUtils.equals(event.userList.id, userList!!.id)) {
getUserListInfo(true)
}
}
@Subscribe
fun onUserListSubscriptionChanged(event: UserListSubscriptionEvent) {
if (userList == null) return
if (TextUtils.equals(event.userList.id, userList!!.id)) {
getUserListInfo(true)
}
}
internal class ParcelableUserListLoader(
context: Context,
private val omitIntentExtra: Boolean,
private val extras: Bundle?,
2017-04-12 14:58:08 +02:00
private val accountKey: UserKey?,
2016-07-02 05:54:53 +02:00
private val listId: String?,
2016-07-02 06:11:07 +02:00
private val listName: String?,
2016-07-02 05:54:53 +02:00
private val userKey: UserKey?,
private val screenName: String?
2017-02-07 16:36:29 +01:00
) : FixedAsyncTaskLoader<SingleResponse<ParcelableUserList>>(context) {
2016-07-02 05:54:53 +02:00
override fun loadInBackground(): SingleResponse<ParcelableUserList> {
if (!omitIntentExtra && extras != null) {
val cache = extras.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)
2017-02-10 16:38:59 +01:00
if (cache != null) return SingleResponse(cache)
2016-07-02 05:54:53 +02:00
}
try {
2017-04-12 14:58:08 +02:00
if (accountKey == null) throw MicroBlogException("No account")
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey)
?: throw MicroBlogException("No account")
2016-07-02 05:54:53 +02:00
val list: UserList
2020-06-08 23:19:10 +02:00
list = when {
2016-07-02 06:11:07 +02:00
listId != null -> {
2020-06-08 23:19:10 +02:00
twitter.showUserList(listId)
2016-07-02 06:11:07 +02:00
}
listName != null && userKey != null -> {
2020-06-08 23:19:10 +02:00
twitter.showUserList(listName, userKey.id)
2016-07-02 06:11:07 +02:00
}
listName != null && screenName != null -> {
2020-06-08 23:19:10 +02:00
twitter.showUserListByScrenName(listName, screenName)
2016-07-02 06:11:07 +02:00
}
else -> {
2017-02-10 16:38:59 +01:00
return SingleResponse(MicroBlogException("Invalid argument"))
2016-07-02 06:11:07 +02:00
}
}
2017-04-21 12:01:54 +02:00
return SingleResponse(list.toParcelable(accountKey))
2016-07-02 05:54:53 +02:00
} catch (e: MicroBlogException) {
2017-02-10 16:38:59 +01:00
return SingleResponse(e)
2016-07-02 05:54:53 +02:00
}
}
override fun onStartLoading() {
2016-07-02 05:54:53 +02:00
forceLoad()
}
}
2016-07-08 07:24:39 +02:00
class UserListDetailsDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val userList = requireArguments().getParcelable<ParcelableUserList>(EXTRA_USER_LIST)!!
val builder = AlertDialog.Builder(requireContext())
2016-07-08 07:24:39 +02:00
builder.setTitle(userList.name)
builder.setMessage(userList.description)
builder.setPositiveButton(android.R.string.ok, null)
builder.neutral(R.string.action_list_creator) {
startActivity(IntentUtils.userProfile(userList.account_key, userList.user_key,
userList.user_screen_name))
}
2017-02-05 14:42:20 +01:00
val dialog = builder.create()
2017-06-19 15:45:41 +02:00
dialog.onShow { it.applyTheme() }
2017-02-05 14:42:20 +01:00
return dialog
2016-07-08 07:24:39 +02:00
}
}
2016-07-02 05:54:53 +02:00
}