improved add/remove from list

This commit is contained in:
Mariotaku Lee 2016-08-30 20:23:59 +08:00
parent f65767ffeb
commit 5ea133b960
21 changed files with 419 additions and 156 deletions

View File

@ -107,10 +107,10 @@ public interface ListResources {
PageableResponseList<UserList> getUserListOwnerships(@Query Paging paging) throws MicroBlogException;
@GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnerships(@Query("user_id") String listMemberId, @Query Paging paging) throws MicroBlogException;
PageableResponseList<UserList> getUserListOwnerships(@Query("user_id") String ownerId, @Query Paging paging) throws MicroBlogException;
@GET("/lists/ownerships.json")
PageableResponseList<UserList> getUserListOwnershipsByScreenName(@Query("screen_name") String listMemberScreenName, @Query Paging paging)
PageableResponseList<UserList> getUserListOwnershipsByScreenName(@Query("screen_name") String ownerScreenName, @Query Paging paging)
throws MicroBlogException;
@GET("/lists/list.json")

View File

@ -145,6 +145,7 @@ public interface IntentConstants {
String EXTRA_USERS = "users";
String EXTRA_ITEMS = "items";
String EXTRA_USER_LIST = "user_list";
String EXTRA_USER_LISTS = "user_lists";
String EXTRA_APPEND_TEXT = "append_text";
String EXTRA_NAME = "name";
String EXTRA_POSITION = "position";

View File

@ -77,6 +77,11 @@ public class ParcelableUserList implements Parcelable, Comparable<ParcelableUser
@JsonField(name = "user_profile_image_url")
public String user_profile_image_url;
/**
* Internal use
*/
public boolean is_user_inside;
public ParcelableUserList() {
}

View File

@ -0,0 +1,38 @@
package org.mariotaku.ktextension
import android.os.Bundle
import android.os.Parcelable
/**
* Created by mariotaku on 16/8/18.
*/
inline fun Bundle(action: Bundle.() -> Unit): Bundle {
val bundle = Bundle()
action(bundle)
return bundle
}
operator fun Bundle.set(key: String, value: Boolean) {
return putBoolean(key, value)
}
operator fun Bundle.set(key: String, value: Int) {
return putInt(key, value)
}
operator fun Bundle.set(key: String, value: Long) {
return putLong(key, value)
}
operator fun Bundle.set(key: String, value: String) {
return putString(key, value)
}
operator fun Bundle.set(key: String, value: Parcelable?) {
return putParcelable(key, value)
}
operator fun Bundle.set(key: String, value: Array<out Parcelable>?) {
return putParcelableArray(key, value)
}

View File

@ -2,7 +2,7 @@ package org.mariotaku.ktextension
import android.os.Parcelable
fun <T> Array<Parcelable>.asTypedArray(creator: Parcelable.Creator<T>): Array<T> {
fun <T> Array<Parcelable>.toTypedArray(creator: Parcelable.Creator<T>): Array<T> {
val result = creator.newArray(size)
System.arraycopy(this, 0, result, 0, size)
return result

View File

@ -35,7 +35,7 @@ import android.widget.AdapterView.OnItemClickListener
import android.widget.ListView
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_account_selector.*
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.sqliteqb.library.Columns
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.R
@ -198,7 +198,7 @@ class AccountSelectorActivity : BaseActivity(), LoaderCallbacks<Cursor?>, OnClic
private val intentExtraIds: Array<UserKey>?
get() {
return intent.getParcelableArrayExtra(EXTRA_ACCOUNT_KEYS)?.asTypedArray(UserKey.CREATOR)
return intent.getParcelableArrayExtra(EXTRA_ACCOUNT_KEYS)?.toTypedArray(UserKey.CREATOR)
}
private val isOAuthOnly: Boolean

View File

@ -65,7 +65,7 @@ import org.apache.commons.lang3.ObjectUtils
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.commons.io.StreamUtils
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.ktextension.setItemChecked
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.Constants.*
@ -540,7 +540,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
if (savedInstanceState != null) {
// Restore from previous saved state
val selected = savedInstanceState.getParcelableArray(EXTRA_ACCOUNT_KEYS).asTypedArray(UserKey.CREATOR)
val selected = savedInstanceState.getParcelableArray(EXTRA_ACCOUNT_KEYS).toTypedArray(UserKey.CREATOR)
accountsAdapter!!.setSelectedAccountIds(*selected)
possiblySensitive = savedInstanceState.getBoolean(EXTRA_IS_POSSIBLY_SENSITIVE)
val mediaList = savedInstanceState.getParcelableArrayList<ParcelableMediaUpdate>(EXTRA_MEDIA)
@ -764,7 +764,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val action = intent.action
val hasAccountIds: Boolean
if (intent.hasExtra(EXTRA_ACCOUNT_KEYS)) {
val accountKeys = intent.getParcelableArrayExtra(EXTRA_ACCOUNT_KEYS).asTypedArray(UserKey.CREATOR)
val accountKeys = intent.getParcelableArrayExtra(EXTRA_ACCOUNT_KEYS).toTypedArray(UserKey.CREATOR)
accountsAdapter!!.setSelectedAccountIds(*accountKeys)
hasAccountIds = true
} else if (intent.hasExtra(EXTRA_ACCOUNT_KEY)) {

View File

@ -101,9 +101,12 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
override fun onPostExecute(result: Boolean?) {
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
activity.executeAfterFragmentResumed {
val activity = it as DataExportActivity
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
}
if (result != null && result) {
activity.setResult(Activity.RESULT_OK)
} else {
@ -113,7 +116,10 @@ class DataExportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
override fun onPreExecute() {
ProgressDialogFragment.show(activity, FRAGMENT_TAG).isCancelable = false
activity.executeAfterFragmentResumed {
val activity = it as DataExportActivity
ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG).isCancelable = false
}
}
companion object {

View File

@ -107,9 +107,10 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
override fun onPostExecute(result: Boolean?) {
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG)
if (f is DialogFragment) {
activity.executeAfterFragmentResumed {
val activity = it as DataImportActivity
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
}
if (result != null && result) {
@ -121,7 +122,10 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
override fun onPreExecute() {
ProgressDialogFragment.show(activity, FRAGMENT_TAG).isCancelable = false
activity.executeAfterFragmentResumed {
val activity = it as DataImportActivity
ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG).isCancelable = false
}
}
companion object {
@ -130,11 +134,11 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
internal class OpenImportTypeTask(private val mActivity: DataImportActivity, private val mPath: String?) : AsyncTask<Any, Any, Int>() {
internal class OpenImportTypeTask(private val activity: DataImportActivity, private val path: String?) : AsyncTask<Any, Any, Int>() {
override fun doInBackground(vararg params: Any): Int? {
if (mPath == null) return 0
val file = File(mPath)
if (path == null) return 0
val file = File(path)
if (!file.isFile) return 0
try {
return DataImportExportUtils.getImportedSettingsFlags(file)
@ -145,26 +149,30 @@ class DataImportActivity : BaseActivity(), DataExportImportTypeSelectorDialogFra
}
override fun onPostExecute(flags: Int?) {
val fm = mActivity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG)
if (f is DialogFragment) {
activity.executeAfterFragmentResumed {
val activity = it as DataImportActivity
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
}
val df = DataExportImportTypeSelectorDialogFragment()
val args = Bundle()
args.putString(EXTRA_PATH, mPath)
args.putString(EXTRA_TITLE, mActivity.getString(R.string.import_settings_type_dialog_title))
args.putString(EXTRA_PATH, path)
args.putString(EXTRA_TITLE, activity.getString(R.string.import_settings_type_dialog_title))
if (flags != null) {
args.putInt(EXTRA_FLAGS, flags)
} else {
args.putInt(EXTRA_FLAGS, 0)
}
df.arguments = args
df.show(mActivity.supportFragmentManager, "select_import_type")
df.show(activity.supportFragmentManager, "select_import_type")
}
override fun onPreExecute() {
ProgressDialogFragment.show(mActivity, FRAGMENT_TAG).isCancelable = false
activity.executeAfterFragmentResumed {
val activity = it as DataImportActivity
ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG).isCancelable = false
}
}
companion object {

View File

@ -36,7 +36,7 @@ import android.widget.Toast
import com.afollestad.appthemeengine.Config
import com.afollestad.appthemeengine.customizers.ATEToolbarCustomizer
import kotlinx.android.synthetic.main.activity_media_viewer.*
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.mediaviewer.library.*
import org.mariotaku.mediaviewer.library.subsampleimageview.SubsampleImageViewerFragment.EXTRA_MEDIA_URI
import org.mariotaku.twidere.R
@ -289,7 +289,7 @@ class MediaViewerActivity : BaseActivity(), IExtendedActivity, ATEToolbarCustomi
get() = intent.getParcelableExtra<ParcelableMedia>(EXTRA_CURRENT_MEDIA)
private val media: Array<ParcelableMedia> by lazy {
intent.getParcelableArrayExtra(EXTRA_MEDIA).asTypedArray(ParcelableMedia.CREATOR)
intent.getParcelableArrayExtra(EXTRA_MEDIA).toTypedArray(ParcelableMedia.CREATOR)
}
protected fun processShareIntent(intent: Intent) {

View File

@ -510,14 +510,20 @@ class SettingsWizardActivity : BaseActivity() {
protected abstract fun nextStep()
override fun onPostExecute(result: Boolean?) {
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
activity.executeAfterFragmentResumed {
val activity = it as SettingsWizardActivity
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG) as DialogFragment
f.dismiss()
}
nextStep()
}
override fun onPreExecute() {
ProgressDialogFragment.show(activity, FRAGMENT_TAG).isCancelable = false
activity.executeAfterFragmentResumed {
val activity = it as SettingsWizardActivity
ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG).isCancelable = false
}
}
private fun wasConfigured(tabs: List<SupportTabSpec>): Boolean {

View File

@ -24,7 +24,7 @@ import android.content.DialogInterface
import android.os.Bundle
import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USERS
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_USER_LIST
@ -80,7 +80,7 @@ class DeleteUserListMembersDialogFragment : BaseDialogFragment(), DialogInterfac
get() {
val args = arguments
if (!args.containsKey(EXTRA_USERS)) return null
return args.getParcelableArray(EXTRA_USERS)?.asTypedArray(ParcelableUser.CREATOR)
return args.getParcelableArray(EXTRA_USERS)?.toTypedArray(ParcelableUser.CREATOR)
}
companion object {

View File

@ -49,6 +49,7 @@ import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.sqliteqb.library.RawItemArray
import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.iface.IExtendedActivity
import org.mariotaku.twidere.adapter.DraftsAdapter
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.model.Draft
@ -289,15 +290,22 @@ class DraftsFragment : BaseSupportFragment(), LoaderCallbacks<Cursor?>, OnItemCl
override fun onPreExecute() {
super.onPreExecute()
val f = ProgressDialogFragment.show(activity, FRAGMENT_TAG_DELETING_DRAFTS)
f.isCancelable = false
(activity as IExtendedActivity).executeAfterFragmentResumed {
val activity = it as FragmentActivity
val f = ProgressDialogFragment.show(activity.supportFragmentManager, FRAGMENT_TAG_DELETING_DRAFTS)
f.isCancelable = false
}
}
override fun onPostExecute(result: Int?) {
super.onPostExecute(result)
val f = activity.supportFragmentManager.findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS)
if (f is DialogFragment) {
f.dismiss()
(activity as IExtendedActivity).executeAfterFragmentResumed {
val activity = it as FragmentActivity
val fm = activity.supportFragmentManager
val f = fm.findFragmentByTag(FRAGMENT_TAG_DELETING_DRAFTS)
if (f is DialogFragment) {
f.dismiss()
}
}
for (id in ids) {
val tag = Uri.withAppendedPath(Drafts.CONTENT_URI, id.toString()).toString()

View File

@ -22,8 +22,7 @@ package org.mariotaku.twidere.fragment
import android.app.Dialog
import android.app.ProgressDialog
import android.os.Bundle
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager
import org.mariotaku.twidere.R
class ProgressDialogFragment : BaseDialogFragment() {
@ -36,9 +35,9 @@ class ProgressDialogFragment : BaseDialogFragment() {
companion object {
fun show(activity: FragmentActivity, tag: String): ProgressDialogFragment {
fun show(fm: FragmentManager, tag: String): ProgressDialogFragment {
val f = ProgressDialogFragment()
f.show(activity.supportFragmentManager, tag)
f.show(fm, tag)
return f
}
}

View File

@ -23,7 +23,7 @@ import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.support.v7.app.AlertDialog
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.model.ParcelableMedia
@ -44,7 +44,7 @@ class SensitiveContentWarningDialogFragment : BaseDialogFragment(), DialogInterf
val status = args.getParcelable<ParcelableStatus>(EXTRA_STATUS)
val option = args.getBundle(EXTRA_ACTIVITY_OPTIONS)
val newDocument = args.getBoolean(EXTRA_NEW_DOCUMENT)
val media = args.getParcelableArray(EXTRA_MEDIA).asTypedArray(ParcelableMedia.CREATOR)
val media = args.getParcelableArray(EXTRA_MEDIA).toTypedArray(ParcelableMedia.CREATOR)
IntentUtils.openMediaDirectly(context, accountKey, status, null, current, media,
option, newDocument)
}

View File

@ -731,11 +731,17 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
private val linkClickHandler: StatusLinkClickHandler
private val linkify: TwidereLinkify
private val locationView: TextView
private val retweetedByView: TextView
init {
this.linkClickHandler = DetailStatusLinkClickHandler(adapter.context,
adapter.multiSelectManager, adapter, adapter.preferences)
this.linkify = TwidereLinkify(linkClickHandler)
locationView = itemView.locationView
retweetedByView = itemView.retweetedBy
initViews()
}
@ -757,11 +763,11 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
if (status.retweet_id != null) {
val retweetedBy = UserColorNameManager.decideDisplayName(status.retweet_user_nickname,
status.retweeted_by_user_name, status.retweeted_by_user_screen_name, nameFirst)
itemView.retweetedBy.text = context.getString(R.string.name_retweeted, retweetedBy)
itemView.retweetedBy.visibility = View.VISIBLE
retweetedByView.text = context.getString(R.string.name_retweeted, retweetedBy)
retweetedByView.visibility = View.VISIBLE
} else {
itemView.retweetedBy.text = null
itemView.retweetedBy.visibility = View.GONE
retweetedByView.text = null
retweetedByView.visibility = View.GONE
}
itemView.profileContainer.drawEnd(status.account_color)
@ -890,27 +896,20 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
itemView.text.visibility = View.VISIBLE
}
val location: ParcelableLocation?
val placeFullName: String?
if (status.is_quote) {
location = status.quoted_location
placeFullName = status.quoted_place_full_name
} else {
location = status.location
placeFullName = status.place_full_name
}
val location: ParcelableLocation? = status.location
val placeFullName: String? = status.place_full_name
if (!TextUtils.isEmpty(placeFullName)) {
itemView.locationView.visibility = View.VISIBLE
itemView.locationView.text = placeFullName
itemView.locationView.isClickable = ParcelableLocationUtils.isValidLocation(location)
locationView.visibility = View.VISIBLE
locationView.text = placeFullName
locationView.isClickable = ParcelableLocationUtils.isValidLocation(location)
} else if (ParcelableLocationUtils.isValidLocation(location)) {
itemView.locationView.visibility = View.VISIBLE
itemView.locationView.setText(R.string.view_map)
itemView.locationView.isClickable = true
locationView.visibility = View.VISIBLE
locationView.setText(R.string.view_map)
locationView.isClickable = true
} else {
itemView.locationView.visibility = View.GONE
itemView.locationView.text = null
locationView.visibility = View.GONE
locationView.text = null
}
val interactUsersAdapter = itemView.countsUsers.adapter as CountsUsersAdapter
@ -930,7 +929,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
itemView.countsUsersHeightHolder.visibility = View.GONE
}
val media = ParcelableMediaUtils.getPrimaryMedia(status)
val media = status.media
if (media?.isEmpty() ?: true) {
itemView.mediaPreviewContainer.visibility = View.GONE
@ -950,6 +949,26 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
itemView.mediaPreview.displayMedia()
}
val quotedMedia = status.quoted_media
if (quotedMedia?.isEmpty() ?: true) {
itemView.quotedMediaPreviewContainer.visibility = View.GONE
itemView.quotedMediaPreview.visibility = View.GONE
itemView.quotedMediaPreviewLoad.visibility = View.GONE
itemView.quotedMediaPreview.displayMedia()
} else if (adapter.isDetailMediaExpanded) {
itemView.quotedMediaPreviewContainer.visibility = View.VISIBLE
itemView.quotedMediaPreview.visibility = View.VISIBLE
itemView.quotedMediaPreviewLoad.visibility = View.GONE
itemView.quotedMediaPreview.displayMedia(media, loader, status.account_key, -1,
adapter.fragment, adapter.mediaLoadingHandler)
} else {
itemView.quotedMediaPreviewContainer.visibility = View.VISIBLE
itemView.quotedMediaPreview.visibility = View.GONE
itemView.quotedMediaPreviewLoad.visibility = View.VISIBLE
itemView.quotedMediaPreview.displayMedia()
}
if (TwitterCardUtils.isCardSupported(status)) {
val size = TwitterCardUtils.getCardSize(status.card!!)
itemView.twitterCard.visibility = View.VISIBLE
@ -1020,7 +1039,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
status.user_screen_name, null, preferences.getBoolean(KEY_NEW_DOCUMENT_API),
Referral.STATUS)
}
itemView.retweetedBy -> {
retweetedByView -> {
if (status.retweet_id != null) {
IntentUtils.openUserProfile(adapter.context, status.account_key,
status.retweeted_by_user_key, status.retweeted_by_user_screen_name,
@ -1028,7 +1047,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
Referral.STATUS)
}
}
itemView.locationView -> {
locationView -> {
val location = status.location
if (!ParcelableLocationUtils.isValidLocation(location)) return
IntentUtils.openMap(adapter.context, location.latitude, location.longitude)
@ -1089,8 +1108,8 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
itemView.mediaPreviewLoad.setOnClickListener(this)
itemView.profileContainer.setOnClickListener(this)
itemView.quotedName.setOnClickListener(this)
itemView.retweetedBy.setOnClickListener(this)
itemView.locationView.setOnClickListener(this)
retweetedByView.setOnClickListener(this)
locationView.setOnClickListener(this)
itemView.quoteOriginalLink.setOnClickListener(this)
itemView.translateLabel.setOnClickListener(this)
@ -1104,7 +1123,7 @@ class StatusFragment : BaseSupportFragment(), LoaderCallbacks<SingleResponse<Par
itemView.quotedText.textSize = textSize * 1.25f
itemView.quoteOriginalLink.textSize = textSize * 0.85f
itemView.locationView.textSize = textSize * 0.85f
locationView.textSize = textSize * 0.85f
itemView.timeSource.textSize = textSize * 0.85f
itemView.translateLabel.textSize = textSize * 0.85f
itemView.translateResult.textSize = textSize * 1.05f

View File

@ -22,7 +22,9 @@ package org.mariotaku.twidere.fragment
import android.animation.ArgbEvaluator
import android.annotation.TargetApi
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Color
import android.graphics.Outline
@ -38,6 +40,7 @@ import android.os.Build
import android.os.Bundle
import android.os.Parcelable
import android.support.annotation.UiThread
import android.support.v4.app.DialogFragment
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.LoaderManager.LoaderCallbacks
@ -47,12 +50,14 @@ import android.support.v4.content.res.ResourcesCompat
import android.support.v4.view.ViewCompat
import android.support.v4.view.ViewPager.OnPageChangeListener
import android.support.v4.view.WindowCompat
import android.support.v7.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.text.SpannableStringBuilder
import android.text.TextUtils
import android.text.util.Linkify
import android.util.Pair
import android.util.SparseBooleanArray
import android.view.*
import android.view.View.OnClickListener
import android.view.View.OnTouchListener
@ -68,17 +73,29 @@ 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.then
import nl.komponents.kovenant.ui.alwaysUi
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.promiseOnUi
import nl.komponents.kovenant.ui.successUi
import org.apache.commons.lang3.ObjectUtils
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.empty
import org.mariotaku.ktextension.set
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.twitter.model.FriendshipUpdate
import org.mariotaku.microblog.library.twitter.model.Relationship
import org.mariotaku.sqliteqb.library.Expression
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.*
import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.activity.ColorPickerDialogActivity
import org.mariotaku.twidere.activity.LinkHandlerActivity
import org.mariotaku.twidere.activity.iface.IExtendedActivity
import org.mariotaku.twidere.adapter.SupportTabsAdapter
import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
@ -883,12 +900,38 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
SetUserNicknameDialogFragment.show(fragmentManager, user.key, nick)
}
R.id.add_to_list -> {
val intent = Intent(INTENT_ACTION_SELECT_USER_LIST)
intent.setClass(activity, UserListSelectorActivity::class.java)
intent.putExtra(EXTRA_ACCOUNT_KEY, user.account_key)
intent.putExtra(EXTRA_SCREEN_NAME, DataStoreUtils.getAccountScreenName(activity,
user.account_key))
startActivityForResult(intent, REQUEST_ADD_TO_LIST)
promiseOnUi {
executeAfterFragmentResumed {
ProgressDialogFragment.show(fragmentManager, "get_list_progress")
}
}.then {
val microBlog = MicroBlogAPIFactory.getInstance(context, user.account_key, true)
val ownedLists = microBlog.getUserListOwnerships(null)
val userListMemberships = microBlog.getUserListMemberships(user.key.id, null, true)
return@then Array<ParcelableUserList>(ownedLists.size) { idx ->
val list = ParcelableUserListUtils.from(ownedLists[idx], user.account_key)
list.is_user_inside = userListMemberships.firstOrNull { it.id == ownedLists[idx].id } != null
return@Array list
}
}.alwaysUi {
executeAfterFragmentResumed {
val df = fragmentManager.findFragmentByTag("get_list_progress") as? DialogFragment
df?.dismiss()
}
}.successUi { result ->
executeAfterFragmentResumed {
val df = AddRemoveUserListDialogFragment()
df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = user.account_key
this[EXTRA_USER_KEY] = user.key
this[EXTRA_USER_LISTS] = result
}
df.show(fragmentManager, "add_remove_list")
}
}.failUi {
Utils.showErrorMessage(context, R.string.action_getting_user_lists, it, false)
}
}
R.id.open_with_account -> {
val intent = Intent(INTENT_ACTION_SELECT_ACCOUNT)
@ -1557,6 +1600,88 @@ class UserFragment : BaseSupportFragment(), OnClickListener, OnLinkClickListener
}
}
class AddRemoveUserListDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val lists = arguments.getParcelableArray(EXTRA_USER_LISTS).toTypedArray(ParcelableUserList.CREATOR)
val userKey = arguments.getParcelable<UserKey>(EXTRA_USER_KEY)
val accountKey = arguments.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.add_or_remove_from_list)
val entries = Array(lists.size) { idx ->
lists[idx].name
}
val states = BooleanArray(lists.size) { idx ->
lists[idx].is_user_inside
}
builder.setPositiveButton(android.R.string.ok, null)
builder.setNeutralButton(R.string.new_user_list, null)
builder.setNegativeButton(android.R.string.cancel, null)
builder.setMultiChoiceItems(entries, states, null)
val dialog = builder.create()
dialog.setOnShowListener {
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
val checkedPositions = dialog.listView.checkedItemPositions
promiseOnUi {
val activity = activity as IExtendedActivity
activity.executeAfterFragmentResumed {
ProgressDialogFragment.show(fragmentManager, "update_lists_progress")
}
}.then {
val twitter = MicroBlogAPIFactory.getInstance(context, accountKey, false)
val successfulStates = SparseBooleanArray()
try {
for (i in 0 until checkedPositions.size()) {
val pos = checkedPositions.keyAt(i)
val checked = checkedPositions.valueAt(i)
if (states[pos] != checked) {
if (checked) {
twitter.addUserListMember(lists[pos].id, userKey.id)
} else {
twitter.deleteUserListMember(lists[pos].id, userKey.id)
}
successfulStates.put(pos, checked)
}
}
} catch (e: MicroBlogException) {
throw UpdateListsException(successfulStates)
}
}.alwaysUi {
val activity = activity as IExtendedActivity
activity.executeAfterFragmentResumed {
val df = fragmentManager.findFragmentByTag("update_lists_progress") as? DialogFragment
df?.dismiss()
}
}.successUi {
dismiss()
}.failUi { e ->
if (e is UpdateListsException) {
val successfulStates = e.successfulStates
for (i in 0 until successfulStates.size()) {
val pos = successfulStates.keyAt(i)
val checked = successfulStates.valueAt(i)
dialog.listView.setItemChecked(pos, checked)
states[pos] = checked
}
}
Utils.showErrorMessage(context, R.string.action_modifying_lists, e, false)
}
}
dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
val df = CreateUserListDialogFragment()
df.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey
}
df.show(fragmentManager, "create_user_list")
}
}
return dialog
}
class UpdateListsException(val successfulStates: SparseBooleanArray) : MicroBlogException()
}
companion object {
private val sArgbEvaluator = ArgbEvaluator()

View File

@ -411,7 +411,8 @@ class UserProfileEditorFragment : BaseSupportFragment(), OnSizeChangedListener,
override fun beforeExecute() {
super.beforeExecute()
callback?.executeAfterFragmentResumed { fragment ->
val df = ProgressDialogFragment.show((fragment as UserProfileEditorFragment).activity, DIALOG_FRAGMENT_TAG)
val fm = (fragment as UserProfileEditorFragment).activity.supportFragmentManager
val df = ProgressDialogFragment.show(fm, DIALOG_FRAGMENT_TAG)
df.isCancelable = false
}
}

View File

@ -42,7 +42,7 @@ import edu.tsinghua.hotmobi.HotMobiLogger
import edu.tsinghua.hotmobi.model.TimelineType
import edu.tsinghua.hotmobi.model.TweetEvent
import org.mariotaku.abstask.library.ManualTaskStarter
import org.mariotaku.ktextension.asTypedArray
import org.mariotaku.ktextension.toTypedArray
import org.mariotaku.ktextension.configure
import org.mariotaku.ktextension.toLong
import org.mariotaku.microblog.library.MicroBlogException
@ -236,7 +236,7 @@ class BackgroundOperationService : IntentService("background_operation"), Consta
val statusParcelables = intent.getParcelableArrayExtra(EXTRA_STATUSES)
val statuses: Array<ParcelableStatusUpdate>
if (statusParcelables != null) {
statuses = statusParcelables.asTypedArray(ParcelableStatusUpdate.CREATOR)
statuses = statusParcelables.toTypedArray(ParcelableStatusUpdate.CREATOR)
} else if (status != null) {
statuses = arrayOf(status)
} else

View File

@ -202,69 +202,11 @@
tools:text="@string/sample_status_text"/>
</LinearLayout>
<org.mariotaku.twidere.view.ForegroundColorView
android:id="@+id/quoteIndicator"
android:layout_width="@dimen/element_spacing_small"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/quoteIndicatorAnchorBottom"
android:layout_alignTop="@+id/quoteIndicatorAnchorTop"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:background="?quoteIndicatorBackgroundColor"
android:visibility="gone"
tools:visibility="visible"/>
<android.support.v4.widget.Space
android:id="@+id/quoteIndicatorAnchorTop"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="@+id/translateContainer"
android:layout_marginTop="@dimen/element_spacing_normal"
android:visibility="visible"/>
<org.mariotaku.twidere.view.NameView
android:id="@+id/quotedName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quoteIndicatorAnchorTop"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:tag="font_family|user"
android:visibility="gone"
app:nv_primaryTextColor="?android:textColorPrimary"
app:nv_secondaryTextColor="?android:textColorSecondary"
app:nv_twoLine="false"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/quotedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quotedName"
android:layout_margin="@dimen/element_spacing_normal"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:singleLine="false"
android:tag="font_family|user"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="?android:textColorPrimary"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<FrameLayout
android:id="@+id/mediaPreviewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quotedText"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:layout_below="@+id/translateContainer"
tools:visibility="visible">
<org.mariotaku.twidere.view.CardMediaContainer
@ -313,34 +255,119 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/mediaPreviewContainer"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:visibility="gone"/>
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/locationView"
<org.mariotaku.twidere.view.ForegroundColorView
android:id="@+id/quoteIndicator"
android:layout_width="@dimen/element_spacing_small"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/quoteIndicatorAnchorBottom"
android:layout_alignTop="@+id/quoteIndicatorAnchorTop"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginStart="@dimen/element_spacing_normal"
android:background="?quoteIndicatorBackgroundColor"
android:visibility="gone"
tools:visibility="visible"/>
<android.support.v4.widget.Space
android:id="@+id/quoteIndicatorAnchorTop"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="@+id/twitterCard"
android:layout_marginTop="@dimen/element_spacing_normal"
android:visibility="visible"/>
<org.mariotaku.twidere.view.NameView
android:id="@+id/quotedName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/twitterCard"
android:layout_below="@+id/quoteIndicatorAnchorTop"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:background="?selectableItemBackground"
android:drawableLeft="@drawable/ic_indicator_location"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_indicator_location"
android:clickable="true"
android:gravity="center_vertical"
android:padding="@dimen/element_spacing_normal"
android:singleLine="true"
android:orientation="horizontal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:tag="font_family|user"
android:text="@string/view_map"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorSecondary"/>
android:visibility="gone"
app:nv_primaryTextColor="?android:textColorPrimary"
app:nv_secondaryTextColor="?android:textColorSecondary"
app:nv_twoLine="false"
tools:visibility="visible"/>
<org.mariotaku.twidere.view.TimelineContentTextView
android:id="@+id/quotedText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quotedName"
android:layout_margin="@dimen/element_spacing_normal"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:singleLine="false"
android:tag="font_family|user"
android:textAppearance="?android:textAppearanceMedium"
android:textColor="?android:textColorPrimary"
android:visibility="gone"
tools:text="@string/sample_status_text"
tools:visibility="visible"/>
<FrameLayout
android:id="@+id/quotedMediaPreviewContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quotedText"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
tools:visibility="visible">
<org.mariotaku.twidere.view.CardMediaContainer
android:id="@+id/quotedMediaPreview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:horizontalSpacing="@dimen/element_spacing_xsmall"
android:verticalSpacing="@dimen/element_spacing_xsmall"
android:visibility="gone">
<include
layout="@layout/layout_card_media_preview"
tools:ignore="DuplicateIncludedIds"/>
</org.mariotaku.twidere.view.CardMediaContainer>
<LinearLayout
android:id="@+id/quotedMediaPreviewLoad"
android:layout_width="match_parent"
android:layout_height="@dimen/action_button_size"
android:layout_gravity="center"
android:background="?selectableItemBackground"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone"
tools:visibility="visible">
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="@drawable/ic_action_gallery"
android:drawableStart="@drawable/ic_action_gallery"
android:gravity="center_vertical"
android:tag="font_family|user"
android:text="@string/load_media"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"/>
</LinearLayout>
</FrameLayout>
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/quoteOriginalLink"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/locationView"
android:layout_below="@+id/quotedMediaPreviewContainer"
android:layout_toEndOf="@+id/quoteIndicator"
android:layout_toRightOf="@+id/quoteIndicator"
android:background="?selectableItemBackground"
@ -362,11 +389,28 @@
android:layout_below="@+id/quoteOriginalLink"
android:visibility="visible"/>
<org.mariotaku.twidere.view.ActionIconThemedTextView
android:id="@+id/locationView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quoteIndicatorAnchorBottom"
android:background="?selectableItemBackground"
android:drawableLeft="@drawable/ic_indicator_location"
android:drawablePadding="4dp"
android:drawableStart="@drawable/ic_indicator_location"
android:gravity="center_vertical"
android:padding="@dimen/element_spacing_normal"
android:singleLine="true"
android:tag="font_family|user"
android:text="@string/view_map"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:textColorSecondary"/>
<LinearLayout
android:id="@+id/countsUsersHeightHolder"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/quoteIndicatorAnchorBottom"
android:layout_below="@+id/locationView"
android:orientation="horizontal"
android:visibility="invisible"
tools:visibility="visible">

View File

@ -293,6 +293,7 @@
<string name="notification_direct_message_multiple_users"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="users_count">%2$d</xliff:g> others sent you <xliff:g id="messages_count">%3$d</xliff:g> direct messages.</string>
<string name="action_getting_status">getting tweet</string>
<string name="action_updating_status">sending tweet</string>
<string name="action_getting_user_lists">getting user lists</string>
<string name="action_sending_direct_message">sending direct message</string>
<string name="action_refreshing_home_timeline">refreshing home timeline</string>
<string name="action_refreshing_mentions">refreshing mentions</string>
@ -312,6 +313,7 @@
<string name="action_unfollowing">unfollowing</string>
<string name="action_creating_list">creating list</string>
<string name="action_adding_member">adding member</string>
<string name="action_modifying_lists">modifying lists</string>
<string name="action_signing_in">signing in</string>
<string name="action_retweeting">retweeting</string>
<string name="action_reporting_for_spam">reporting for spam</string>
@ -812,4 +814,5 @@
<string name="hide_replies">Hide replies</string>
<string name="no_extension_installed">No extension installed</string>
<string name="pinned_status">Pinned tweet</string>
<string name="add_or_remove_from_list">Add or remove from list</string>
</resources>