421 lines
17 KiB
Kotlin
421 lines
17 KiB
Kotlin
/*
|
|
* 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
|
|
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
|
|
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
|
|
import org.mariotaku.kpreferences.get
|
|
import org.mariotaku.ktextension.setItemAvailability
|
|
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
|
|
import org.mariotaku.twidere.activity.UserSelectorActivity
|
|
import org.mariotaku.twidere.adapter.SupportTabsAdapter
|
|
import org.mariotaku.twidere.app.TwidereApplication
|
|
import org.mariotaku.twidere.constant.newDocumentApiKey
|
|
import org.mariotaku.twidere.extension.applyTheme
|
|
import org.mariotaku.twidere.extension.model.api.microblog.toParcelable
|
|
import org.mariotaku.twidere.extension.neutral
|
|
import org.mariotaku.twidere.extension.onShow
|
|
import org.mariotaku.twidere.fragment.iface.IBaseFragment.SystemWindowInsetsCallback
|
|
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
|
|
import org.mariotaku.twidere.fragment.statuses.UserListTimelineFragment
|
|
import org.mariotaku.twidere.fragment.users.UserListMembersFragment
|
|
import org.mariotaku.twidere.fragment.users.UserListSubscribersFragment
|
|
import org.mariotaku.twidere.model.ParcelableUser
|
|
import org.mariotaku.twidere.model.ParcelableUserList
|
|
import org.mariotaku.twidere.model.SingleResponse
|
|
import org.mariotaku.twidere.model.UserKey
|
|
import org.mariotaku.twidere.model.event.UserListSubscriptionEvent
|
|
import org.mariotaku.twidere.model.event.UserListUpdatedEvent
|
|
import org.mariotaku.twidere.util.*
|
|
import org.mariotaku.twidere.util.shortcut.ShortcutCreator
|
|
|
|
class UserListFragment : AbsToolbarTabPagesFragment(), OnClickListener,
|
|
LoaderCallbacks<SingleResponse<ParcelableUserList>>, SystemWindowInsetsCallback,
|
|
SupportFragmentCallback {
|
|
|
|
private var userListLoaderInitialized: Boolean = false
|
|
|
|
var userList: ParcelableUserList? = null
|
|
private set
|
|
|
|
fun displayUserList(userList: ParcelableUserList?) {
|
|
val activity = activity ?: return
|
|
LoaderManager.getInstance(this).destroyLoader(0)
|
|
this.userList = userList
|
|
|
|
if (userList != null) {
|
|
activity.title = userList.name
|
|
} else {
|
|
activity.setTitle(R.string.title_user_list)
|
|
}
|
|
activity.invalidateOptionsMenu()
|
|
}
|
|
|
|
fun getUserListInfo(omitIntentExtra: Boolean) {
|
|
val lm = LoaderManager.getInstance(this)
|
|
lm.destroyLoader(0)
|
|
val args = Bundle(arguments)
|
|
args.putBoolean(EXTRA_OMIT_INTENT_EXTRA, omitIntentExtra)
|
|
if (!userListLoaderInitialized) {
|
|
lm.initLoader(0, args, this)
|
|
userListLoaderInitialized = true
|
|
} 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
|
|
if (resultCode != Activity.RESULT_OK || !data!!.hasExtra(EXTRA_USER) || userList == null)
|
|
return
|
|
val user = data.getParcelableExtra<ParcelableUser>(EXTRA_USER) ?: return
|
|
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)
|
|
activity?.let {
|
|
IntentUtils.openUserListDetails(it, accountKey, userList!!.id,
|
|
userList.user_key, userList.user_screen_name, userList.name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
super.onActivityResult(requestCode, resultCode, data)
|
|
}
|
|
|
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
|
super.onActivityCreated(savedInstanceState)
|
|
val activity = activity
|
|
setHasOptionsMenu(true)
|
|
|
|
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))))
|
|
})
|
|
}
|
|
|
|
getUserListInfo(false)
|
|
}
|
|
|
|
override fun addTabs(adapter: SupportTabsAdapter) {
|
|
val args = arguments ?: return
|
|
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))
|
|
}
|
|
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))
|
|
adapter.add(cls = UserListSubscribersFragment::class.java, args = tabArgs, name = getString(R.string.title_userlist_subscribers))
|
|
}
|
|
|
|
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)
|
|
super.onDestroyView()
|
|
}
|
|
|
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
|
inflater.inflate(R.menu.menu_user_list, menu)
|
|
}
|
|
|
|
override fun onPrepareOptionsMenu(menu: Menu) {
|
|
val userList = this.userList
|
|
menu.setItemAvailability(R.id.info, userList != null)
|
|
menu.removeGroup(MENU_GROUP_USER_LIST_EXTENSION)
|
|
if (userList != null) {
|
|
val isMyList = userList.user_key == userList.account_key
|
|
val isFollowing = userList.is_following
|
|
menu.setItemAvailability(R.id.edit, isMyList)
|
|
menu.setItemAvailability(R.id.follow, !isMyList)
|
|
menu.setItemAvailability(R.id.add, isMyList)
|
|
menu.setItemAvailability(R.id.delete, isMyList)
|
|
val followItem = menu.findItem(R.id.follow)
|
|
if (isFollowing) {
|
|
followItem.setIcon(R.drawable.ic_action_cancel)
|
|
followItem.setTitle(R.string.action_unsubscribe)
|
|
} else {
|
|
followItem.setIcon(R.drawable.ic_action_add)
|
|
followItem.setTitle(R.string.action_subscribe)
|
|
}
|
|
val extensionsIntent = Intent(INTENT_ACTION_EXTENSION_OPEN_USER_LIST)
|
|
extensionsIntent.setExtrasClassLoader(TwidereApplication::class.java.classLoader)
|
|
extensionsIntent.putExtra(EXTRA_USER_LIST, userList)
|
|
activity?.let {
|
|
MenuUtils.addIntentToMenu(it, menu, extensionsIntent, MENU_GROUP_USER_LIST_EXTENSION)
|
|
menu.setItemAvailability(R.id.add_to_home_screen_submenu, ShortcutManagerCompat.isRequestPinShortcutSupported(it))
|
|
}
|
|
} else {
|
|
menu.setItemAvailability(R.id.edit, false)
|
|
menu.setItemAvailability(R.id.follow, false)
|
|
menu.setItemAvailability(R.id.add, false)
|
|
menu.setItemAvailability(R.id.delete, false)
|
|
menu.setItemAvailability(R.id.add_to_home_screen_submenu, false)
|
|
}
|
|
}
|
|
|
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
val twitter = twitterWrapper
|
|
val userList = userList ?: return false
|
|
val activity = activity ?: return false
|
|
val fragmentManager = parentFragmentManager
|
|
when (item.itemId) {
|
|
R.id.add -> {
|
|
if (userList.user_key != userList.account_key) return false
|
|
val intent = Intent(INTENT_ACTION_SELECT_USER)
|
|
intent.setClass(activity, UserSelectorActivity::class.java)
|
|
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)
|
|
}
|
|
R.id.info -> {
|
|
val df = UserListDetailsDialogFragment()
|
|
df.arguments = Bundle().apply {
|
|
putParcelable(EXTRA_USER_LIST, userList)
|
|
}
|
|
df.show(childFragmentManager, "user_list_details")
|
|
}
|
|
R.id.add_statuses_to_home_screen -> {
|
|
ShortcutCreator.performCreation(this) {
|
|
ShortcutCreator.userListTimeline(activity, userList.account_key, userList)
|
|
}
|
|
}
|
|
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)
|
|
}
|
|
R.id.profileImage -> {
|
|
val userList = this.userList ?: return
|
|
activity?.let {
|
|
IntentUtils.openUserProfile(it, userList.account_key, userList.user_key,
|
|
userList.user_screen_name, null, preferences[newDocumentApiKey], null)
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
override fun onCreateLoader(id: Int, args: Bundle?): Loader<SingleResponse<ParcelableUserList>> {
|
|
val accountKey = args!!.getParcelable<UserKey?>(EXTRA_ACCOUNT_KEY)
|
|
val userKey = args.getParcelable<UserKey?>(EXTRA_USER_KEY)
|
|
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,
|
|
listName, userKey, screenName)
|
|
}
|
|
|
|
override fun onLoadFinished(loader: Loader<SingleResponse<ParcelableUserList>>,
|
|
data: SingleResponse<ParcelableUserList>?) {
|
|
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?,
|
|
private val accountKey: UserKey?,
|
|
private val listId: String?,
|
|
private val listName: String?,
|
|
private val userKey: UserKey?,
|
|
private val screenName: String?
|
|
) : FixedAsyncTaskLoader<SingleResponse<ParcelableUserList>>(context) {
|
|
|
|
override fun loadInBackground(): SingleResponse<ParcelableUserList> {
|
|
if (!omitIntentExtra && extras != null) {
|
|
val cache = extras.getParcelable<ParcelableUserList>(EXTRA_USER_LIST)
|
|
if (cache != null) return SingleResponse(cache)
|
|
}
|
|
try {
|
|
if (accountKey == null) throw MicroBlogException("No account")
|
|
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey)
|
|
?: throw MicroBlogException("No account")
|
|
val list: UserList
|
|
list = when {
|
|
listId != null -> {
|
|
twitter.showUserList(listId)
|
|
}
|
|
listName != null && userKey != null -> {
|
|
twitter.showUserList(listName, userKey.id)
|
|
}
|
|
listName != null && screenName != null -> {
|
|
twitter.showUserListByScrenName(listName, screenName)
|
|
}
|
|
else -> {
|
|
return SingleResponse(MicroBlogException("Invalid argument"))
|
|
}
|
|
}
|
|
return SingleResponse(list.toParcelable(accountKey))
|
|
} catch (e: MicroBlogException) {
|
|
return SingleResponse(e)
|
|
}
|
|
|
|
}
|
|
|
|
override fun onStartLoading() {
|
|
forceLoad()
|
|
}
|
|
|
|
}
|
|
|
|
class UserListDetailsDialogFragment : BaseDialogFragment() {
|
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
val userList = requireArguments().getParcelable<ParcelableUserList>(EXTRA_USER_LIST)!!
|
|
val builder = AlertDialog.Builder(requireContext())
|
|
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))
|
|
}
|
|
val dialog = builder.create()
|
|
dialog.onShow { it.applyTheme() }
|
|
return dialog
|
|
}
|
|
}
|
|
|
|
}
|