rewrite update status logic

close #506
close #539
This commit is contained in:
Mariotaku Lee 2017-02-08 17:36:47 +08:00
parent 8f7fd2b330
commit 632db4ad0c
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
16 changed files with 297 additions and 153 deletions

View File

@ -31,6 +31,10 @@ import android.support.annotation.Nullable;
import org.mariotaku.twidere.constant.IntentConstants; import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.util.ServiceUtils.ServiceToken; import org.mariotaku.twidere.util.ServiceUtils.ServiceToken;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public abstract class AbsServiceInterface<I extends IInterface> implements IInterface { public abstract class AbsServiceInterface<I extends IInterface> implements IInterface {
private final Context mContext; private final Context mContext;
@ -40,27 +44,10 @@ public abstract class AbsServiceInterface<I extends IInterface> implements IInte
private I mIInterface; private I mIInterface;
private ServiceToken mToken; private ServiceToken mToken;
private boolean mDisconnected;
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName service, final IBinder obj) {
mIInterface = AbsServiceInterface.this.onServiceConnected(service, obj);
mDisconnected = false;
}
@Override
public void onServiceDisconnected(final ComponentName service) {
mIInterface = null;
mDisconnected = true;
}
};
protected abstract I onServiceConnected(ComponentName service, IBinder obj); protected abstract I onServiceConnected(ComponentName service, IBinder obj);
protected AbsServiceInterface(final Context context, final String componentName, @Nullable final Bundle metaData) { protected AbsServiceInterface(final Context context, final String componentName, @Nullable final Bundle metaData) {
mDisconnected = true;
mContext = context; mContext = context;
mShortenerName = componentName; mShortenerName = componentName;
mMetaData = metaData; mMetaData = metaData;
@ -86,19 +73,38 @@ public abstract class AbsServiceInterface<I extends IInterface> implements IInte
final Intent intent = new Intent(IntentConstants.INTENT_ACTION_EXTENSION_SHORTEN_STATUS); final Intent intent = new Intent(IntentConstants.INTENT_ACTION_EXTENSION_SHORTEN_STATUS);
final ComponentName component = ComponentName.unflattenFromString(mShortenerName); final ComponentName component = ComponentName.unflattenFromString(mShortenerName);
intent.setComponent(component); intent.setComponent(component);
mDisconnected = true; final FutureTask<Boolean> futureTask = new FutureTask<>(new Callable<Boolean>() {
mToken = ServiceUtils.bindToService(mContext, intent, mConnection); @Override
if (mToken == null) return false; public Boolean call() throws Exception {
mDisconnected = false; return mIInterface != null;
while (mIInterface == null && !mDisconnected) {
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
// Ignore
return false;
} }
});
mToken = ServiceUtils.bindToService(mContext, intent, new ServiceConnection() {
@Override
public void onServiceConnected(final ComponentName name, final IBinder obj) {
mIInterface = AbsServiceInterface.this.onServiceConnected(name, obj);
if (!futureTask.isDone() && !futureTask.isCancelled()) {
futureTask.run();
}
}
@Override
public void onServiceDisconnected(final ComponentName name) {
mIInterface = null;
if (!futureTask.isDone() && !futureTask.isCancelled()) {
futureTask.run();
}
}
});
if (mToken == null) return false;
try {
return futureTask.get();
} catch (InterruptedException e) {
return false;
} catch (ExecutionException e) {
return false;
} }
return true;
} }
public final void checkService(CheckServiceAction action) throws CheckServiceException { public final void checkService(CheckServiceAction action) throws CheckServiceException {

View File

@ -49,7 +49,7 @@ public final class ServiceUtils {
return new ServiceToken(cw); return new ServiceToken(cw);
} }
} }
Log.e(LOGTAG, "Failed to bind to service"); DebugLog.w(LOGTAG, "Failed to bind to service", null);
return null; return null;
} }

View File

@ -129,6 +129,7 @@ class AccountSelectorActivity : BaseActivity(), OnItemClickListener {
} }
val data = Intent() val data = Intent()
data.putExtra(EXTRA_IDS, checkedIds) data.putExtra(EXTRA_IDS, checkedIds)
data.putExtra(EXTRA_EXTRAS, intent.getBundleExtra(EXTRA_EXTRAS))
setResult(Activity.RESULT_OK, data) setResult(Activity.RESULT_OK, data)
finish() finish()
} }
@ -143,6 +144,7 @@ class AccountSelectorActivity : BaseActivity(), OnItemClickListener {
val data = Intent() val data = Intent()
data.putExtra(EXTRA_ID, account.key.id) data.putExtra(EXTRA_ID, account.key.id)
data.putExtra(EXTRA_ACCOUNT_KEY, account.key) data.putExtra(EXTRA_ACCOUNT_KEY, account.key)
data.putExtra(EXTRA_EXTRAS, intent.getBundleExtra(EXTRA_EXTRAS))
val startIntent = startIntent val startIntent = startIntent
if (startIntent != null) { if (startIntent != null) {

View File

@ -356,6 +356,8 @@ class ParcelableActivitiesAdapter(
fun onStatusActionClick(holder: IStatusViewHolder, id: Int, position: Int) fun onStatusActionClick(holder: IStatusViewHolder, id: Int, position: Int)
fun onStatusActionLongClick(holder: IStatusViewHolder, id: Int, position: Int): Boolean
fun onStatusMenuClick(holder: IStatusViewHolder, menuView: View, position: Int) fun onStatusMenuClick(holder: IStatusViewHolder, menuView: View, position: Int)
fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, position: Int) fun onMediaClick(holder: IStatusViewHolder, view: View, media: ParcelableMedia, position: Int)
@ -398,8 +400,13 @@ class ParcelableActivitiesAdapter(
} }
override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) { override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) {
val adapter = adapterRef.get() ?: return val listener = adapterRef.get()?.activityAdapterListener ?: return
adapter.activityAdapterListener?.onStatusActionClick(holder as IStatusViewHolder, id, position) listener.onStatusActionClick(holder as IStatusViewHolder, id, position)
}
override fun onItemActionLongClick(holder: RecyclerView.ViewHolder, id: Int, position: Int): Boolean {
val listener = adapterRef.get()?.activityAdapterListener ?: return false
return listener.onStatusActionLongClick(holder as IStatusViewHolder, id, position)
} }
override fun onStatusLongClick(holder: IStatusViewHolder, position: Int): Boolean { override fun onStatusLongClick(holder: IStatusViewHolder, position: Int): Boolean {

View File

@ -28,5 +28,7 @@ import android.view.View
interface ContentCardClickListener { interface ContentCardClickListener {
fun onItemActionClick(holder: ViewHolder, id: Int, position: Int) {} fun onItemActionClick(holder: ViewHolder, id: Int, position: Int) {}
fun onItemActionLongClick(holder: ViewHolder, id: Int, position: Int): Boolean = false
fun onItemMenuClick(holder: ViewHolder, menuView: View, position: Int) {} fun onItemMenuClick(holder: ViewHolder, menuView: View, position: Int) {}
} }

View File

@ -20,6 +20,7 @@
package org.mariotaku.twidere.fragment package org.mariotaku.twidere.fragment
import android.accounts.AccountManager import android.accounts.AccountManager
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
@ -49,8 +50,12 @@ import org.mariotaku.twidere.adapter.ParcelableActivitiesAdapter.Companion.ITEM_
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
import org.mariotaku.twidere.annotation.ReadPositionTag import org.mariotaku.twidere.annotation.ReadPositionTag
import org.mariotaku.twidere.constant.* import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.* import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
import org.mariotaku.twidere.constant.displaySensitiveContentsKey
import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.constant.readFromBottomKey
import org.mariotaku.twidere.constant.rememberPositionKey
import org.mariotaku.twidere.extension.model.getAccountType import org.mariotaku.twidere.extension.model.getAccountType
import org.mariotaku.twidere.fragment.AbsStatusesFragment.DefaultOnLikedListener import org.mariotaku.twidere.fragment.AbsStatusesFragment.DefaultOnLikedListener
import org.mariotaku.twidere.loader.iface.IExtendedLoader import org.mariotaku.twidere.loader.iface.IExtendedLoader
@ -101,11 +106,20 @@ abstract class AbsActivitiesFragment protected constructor() :
pauseOnScrollListener = PauseRecyclerViewOnScrollListener(adapter.mediaLoader.imageLoader, false, true) pauseOnScrollListener = PauseRecyclerViewOnScrollListener(adapter.mediaLoader.imageLoader, false, true)
val loaderArgs = Bundle(arguments) val loaderArgs = Bundle(arguments)
loaderArgs.putBoolean(IntentConstants.EXTRA_FROM_USER, true) loaderArgs.putBoolean(EXTRA_FROM_USER, true)
loaderManager.initLoader(0, loaderArgs, this) loaderManager.initLoader(0, loaderArgs, this)
showProgress() showProgress()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
AbsStatusesFragment.REQUEST_FAVORITE_SELECT_ACCOUNT,
AbsStatusesFragment.REQUEST_RETWEET_SELECT_ACCOUNT -> {
AbsStatusesFragment.handleActionActivityResult(this, requestCode, resultCode, data)
}
}
}
abstract fun getActivities(param: RefreshTaskParam): Boolean abstract fun getActivities(param: RefreshTaskParam): Boolean
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean { override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
@ -133,8 +147,8 @@ abstract class AbsActivitiesFragment protected constructor() :
if (action == null) return false if (action == null) return false
when (action) { when (action) {
ACTION_STATUS_REPLY -> { ACTION_STATUS_REPLY -> {
val intent = Intent(IntentConstants.INTENT_ACTION_REPLY) val intent = Intent(INTENT_ACTION_REPLY)
intent.putExtra(IntentConstants.EXTRA_STATUS, status) intent.putExtra(EXTRA_STATUS, status)
startActivity(intent) startActivity(intent)
return true return true
} }
@ -185,8 +199,8 @@ abstract class AbsActivitiesFragment protected constructor() :
} }
override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ParcelableActivity>> { override fun onCreateLoader(id: Int, args: Bundle): Loader<List<ParcelableActivity>> {
val fromUser = args.getBoolean(IntentConstants.EXTRA_FROM_USER) val fromUser = args.getBoolean(EXTRA_FROM_USER)
args.remove(IntentConstants.EXTRA_FROM_USER) args.remove(EXTRA_FROM_USER)
return onCreateActivitiesLoader(activity, args, fromUser) return onCreateActivitiesLoader(activity, args, fromUser)
} }
@ -317,9 +331,9 @@ abstract class AbsActivitiesFragment protected constructor() :
val activity = activity val activity = activity
when (id) { when (id) {
R.id.reply -> { R.id.reply -> {
val intent = Intent(IntentConstants.INTENT_ACTION_REPLY) val intent = Intent(INTENT_ACTION_REPLY)
intent.`package` = activity.packageName intent.`package` = activity.packageName
intent.putExtra(IntentConstants.EXTRA_STATUS, status) intent.putExtra(EXTRA_STATUS, status)
activity.startActivity(intent) activity.startActivity(intent)
} }
R.id.retweet -> { R.id.retweet -> {
@ -335,6 +349,11 @@ abstract class AbsActivitiesFragment protected constructor() :
} }
} }
override fun onStatusActionLongClick(holder: IStatusViewHolder, id: Int, position: Int): Boolean {
val status = getActivityStatus(position) ?: return false
return AbsStatusesFragment.handleActionLongClick(this, status, adapter.getItemId(position), id)
}
override fun onActivityClick(holder: ActivityTitleSummaryViewHolder, position: Int) { override fun onActivityClick(holder: ActivityTitleSummaryViewHolder, position: Int) {
val activity = adapter.getActivity(position) ?: return val activity = adapter.getActivity(position) ?: return
val list = ArrayList<Parcelable>() val list = ArrayList<Parcelable>()

View File

@ -20,10 +20,12 @@
package org.mariotaku.twidere.fragment package org.mariotaku.twidere.fragment
import android.accounts.AccountManager import android.accounts.AccountManager
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v4.app.LoaderManager.LoaderCallbacks import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.content.Loader import android.support.v4.content.Loader
@ -36,22 +38,18 @@ import edu.tsinghua.hotmobi.HotMobiLogger
import edu.tsinghua.hotmobi.model.MediaEvent import edu.tsinghua.hotmobi.model.MediaEvent
import kotlinx.android.synthetic.main.fragment_content_recyclerview.* import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.coerceInOr import org.mariotaku.ktextension.*
import org.mariotaku.ktextension.isNullOrEmpty
import org.mariotaku.ktextension.rangeOfSize
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants import org.mariotaku.twidere.TwidereConstants
import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
import org.mariotaku.twidere.annotation.ReadPositionTag import org.mariotaku.twidere.annotation.ReadPositionTag
import org.mariotaku.twidere.annotation.Referral import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.*
import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.KeyboardShortcutConstants.* import org.mariotaku.twidere.constant.KeyboardShortcutConstants.*
import org.mariotaku.twidere.constant.displaySensitiveContentsKey
import org.mariotaku.twidere.constant.newDocumentApiKey
import org.mariotaku.twidere.constant.readFromBottomKey
import org.mariotaku.twidere.constant.rememberPositionKey
import org.mariotaku.twidere.extension.model.getAccountType import org.mariotaku.twidere.extension.model.getAccountType
import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable import org.mariotaku.twidere.graphic.like.LikeAnimationDrawable
import org.mariotaku.twidere.loader.iface.IExtendedLoader import org.mariotaku.twidere.loader.iface.IExtendedLoader
@ -70,8 +68,7 @@ import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder
/** /**
* Created by mariotaku on 14/11/5. * Created by mariotaku on 14/11/5.
*/ */
abstract class AbsStatusesFragment protected constructor() : abstract class AbsStatusesFragment : AbsContentListRecyclerViewFragment<ParcelableStatusesAdapter>(),
AbsContentListRecyclerViewFragment<ParcelableStatusesAdapter>(),
LoaderCallbacks<List<ParcelableStatus>?>, IStatusViewHolder.StatusClickListener, LoaderCallbacks<List<ParcelableStatus>?>, IStatusViewHolder.StatusClickListener,
KeyboardShortcutCallback { KeyboardShortcutCallback {
@ -163,6 +160,14 @@ abstract class AbsStatusesFragment protected constructor() :
super.onDestroy() super.onDestroy()
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_FAVORITE_SELECT_ACCOUNT, REQUEST_RETWEET_SELECT_ACCOUNT -> {
handleActionActivityResult(this, requestCode, resultCode, data)
}
}
}
abstract fun getStatuses(param: RefreshTaskParam): Boolean abstract fun getStatuses(param: RefreshTaskParam): Boolean
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean { override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
@ -370,7 +375,12 @@ abstract class AbsStatusesFragment protected constructor() :
override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) { override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) {
val status = adapter.getStatus(position) ?: return val status = adapter.getStatus(position) ?: return
handleStatusActionClick(context, fragmentManager, twitterWrapper, holder as StatusViewHolder, status, id) handleActionClick(context, fragmentManager, twitterWrapper, holder as StatusViewHolder, status, id)
}
override fun onItemActionLongClick(holder: RecyclerView.ViewHolder, id: Int, position: Int): Boolean {
val status = adapter.getStatus(position) ?: return false
return handleActionLongClick(this, status, adapter.getItemId(position), id)
} }
override fun createItemDecoration(context: Context, recyclerView: RecyclerView, layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? { override fun createItemDecoration(context: Context, recyclerView: RecyclerView, layoutManager: LinearLayoutManager): RecyclerView.ItemDecoration? {
@ -508,12 +518,13 @@ abstract class AbsStatusesFragment protected constructor() :
class DefaultOnLikedListener( class DefaultOnLikedListener(
private val twitter: AsyncTwitterWrapper, private val twitter: AsyncTwitterWrapper,
private val status: ParcelableStatus private val status: ParcelableStatus,
private val accountKey: UserKey? = null
) : LikeAnimationDrawable.OnLikedListener { ) : LikeAnimationDrawable.OnLikedListener {
override fun onLiked(): Boolean { override fun onLiked(): Boolean {
if (status.is_favorite) return false if (status.is_favorite) return false
twitter.createFavoriteAsync(status.account_key, status) twitter.createFavoriteAsync(accountKey ?: status.account_key, status)
return true return true
} }
} }
@ -533,11 +544,11 @@ abstract class AbsStatusesFragment protected constructor() :
companion object { companion object {
fun handleStatusActionClick(context: Context, fm: FragmentManager, const val REQUEST_FAVORITE_SELECT_ACCOUNT = 101
twitter: AsyncTwitterWrapper?, holder: StatusViewHolder, const val REQUEST_RETWEET_SELECT_ACCOUNT = 102
status: ParcelableStatus?, id: Int) {
if (status == null) return fun handleActionClick(context: Context, fm: FragmentManager, twitter: AsyncTwitterWrapper?,
holder: StatusViewHolder, status: ParcelableStatus, id: Int) {
when (id) { when (id) {
R.id.reply -> { R.id.reply -> {
val intent = Intent(INTENT_ACTION_REPLY) val intent = Intent(INTENT_ACTION_REPLY)
@ -553,11 +564,58 @@ abstract class AbsStatusesFragment protected constructor() :
if (status.is_favorite) { if (status.is_favorite) {
twitter.destroyFavoriteAsync(status.account_key, status.id) twitter.destroyFavoriteAsync(status.account_key, status.id)
} else { } else {
holder.playLikeAnimation(DefaultOnLikedListener(twitter, holder.playLikeAnimation(DefaultOnLikedListener(twitter, status))
status))
} }
} }
} }
} }
fun handleActionLongClick(fragment: Fragment, status: ParcelableStatus, itemId: Long, id: Int): Boolean {
when (id) {
R.id.favorite -> {
val intent = selectAccountIntent(fragment.context, status, itemId)
fragment.startActivityForResult(intent, REQUEST_FAVORITE_SELECT_ACCOUNT)
return true
}
R.id.retweet -> {
val intent = selectAccountIntent(fragment.context, status, itemId)
fragment.startActivityForResult(intent, REQUEST_RETWEET_SELECT_ACCOUNT)
return true
}
}
return false
}
fun handleActionActivityResult(fragment: BaseFragment, requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
AbsStatusesFragment.REQUEST_FAVORITE_SELECT_ACCOUNT -> {
if (resultCode != Activity.RESULT_OK || data == null) return
val accountKey = data.getParcelableExtra<UserKey>(IntentConstants.EXTRA_ACCOUNT_KEY)
val extras = data.getBundleExtra(IntentConstants.EXTRA_EXTRAS)
val status = extras.getParcelable<ParcelableStatus>(IntentConstants.EXTRA_STATUS)
fragment.twitterWrapper.createFavoriteAsync(accountKey, status)
}
AbsStatusesFragment.REQUEST_RETWEET_SELECT_ACCOUNT -> {
if (resultCode != Activity.RESULT_OK || data == null) return
val accountKey = data.getParcelableExtra<UserKey>(IntentConstants.EXTRA_ACCOUNT_KEY)
val extras = data.getBundleExtra(IntentConstants.EXTRA_EXTRAS)
val status = extras.getParcelable<ParcelableStatus>(IntentConstants.EXTRA_STATUS)
RetweetQuoteDialogFragment.show(fragment.childFragmentManager, status, accountKey)
}
}
}
fun selectAccountIntent(context: Context, status: ParcelableStatus, itemId: Long): Intent {
val intent = Intent(context, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SELECT_ONLY_ITEM_AUTOMATICALLY, true)
intent.putExtra(EXTRA_ACCOUNT_HOST, status.account_key.host)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
intent.putExtra(EXTRA_EXTRAS, Bundle {
this[EXTRA_STATUS] = status
this[EXTRA_ID] = itemId
})
return intent
}
} }
} }

View File

@ -97,7 +97,7 @@ class ExtensionsListFragment : AbsContentListViewFragment<ExtensionsAdapter>(),
inflater.inflate(R.menu.action_extension, menu) inflater.inflate(R.menu.action_extension, menu)
val adapterMenuInfo = menuInfo as AdapterContextMenuInfo val adapterMenuInfo = menuInfo as AdapterContextMenuInfo
val extensionInfo = adapter.getItem(adapterMenuInfo.position) val extensionInfo = adapter.getItem(adapterMenuInfo.position)
if (extensionInfo.pname != null && extensionInfo.settings != null) { if (extensionInfo.settings != null) {
val intent = Intent(IntentConstants.INTENT_ACTION_EXTENSION_SETTINGS) val intent = Intent(IntentConstants.INTENT_ACTION_EXTENSION_SETTINGS)
intent.setClassName(extensionInfo.pname, extensionInfo.settings) intent.setClassName(extensionInfo.pname, extensionInfo.settings)
menu.setItemAvailability(R.id.settings, packageManager!!.queryIntentActivities(intent, 0).size == 1) menu.setItemAvailability(R.id.settings, packageManager!!.queryIntentActivities(intent, 0).size == 1)

View File

@ -62,10 +62,16 @@ class ItemsListFragment : AbsContentListRecyclerViewFragment<VariousItemsAdapter
override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) { override fun onItemActionClick(holder: RecyclerView.ViewHolder, id: Int, position: Int) {
val status = dummyItemAdapter.getStatus(position) ?: return val status = dummyItemAdapter.getStatus(position) ?: return
AbsStatusesFragment.handleStatusActionClick(context, fragmentManager, AbsStatusesFragment.handleActionClick(context, fragmentManager,
twitterWrapper, holder as StatusViewHolder, status, id) twitterWrapper, holder as StatusViewHolder, status, id)
} }
override fun onItemActionLongClick(holder: RecyclerView.ViewHolder, id: Int, position: Int): Boolean {
val status = dummyItemAdapter.getStatus(position) ?: return false
return AbsStatusesFragment.handleActionLongClick(this@ItemsListFragment, status,
adapter.getItemId(position), id)
}
override fun onItemMenuClick(holder: RecyclerView.ViewHolder, menuView: View, position: Int) { override fun onItemMenuClick(holder: RecyclerView.ViewHolder, menuView: View, position: Int) {
if (activity == null) return if (activity == null) return
val view = layoutManager.findViewByPosition(position) ?: return val view = layoutManager.findViewByPosition(position) ?: return
@ -101,6 +107,15 @@ class ItemsListFragment : AbsContentListRecyclerViewFragment<VariousItemsAdapter
return adapter return adapter
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
AbsStatusesFragment.REQUEST_FAVORITE_SELECT_ACCOUNT,
AbsStatusesFragment.REQUEST_RETWEET_SELECT_ACCOUNT -> {
AbsStatusesFragment.handleActionActivityResult(this, requestCode, resultCode, data)
}
}
}
override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<*>?> { override fun onCreateLoader(id: Int, args: Bundle?): Loader<List<*>?> {
return ItemsLoader(context, arguments) return ItemsLoader(context, arguments)
} }

View File

@ -35,6 +35,8 @@ import android.view.Gravity
import android.view.View import android.view.View
import android.widget.EditText import android.widget.EditText
import com.twitter.Validator import com.twitter.Validator
import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set
import org.mariotaku.ktextension.setItemAvailability import org.mariotaku.ktextension.setItemAvailability
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.DummyItemAdapter import org.mariotaku.twidere.adapter.DummyItemAdapter
@ -42,10 +44,7 @@ import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_QUICK_SEND import org.mariotaku.twidere.constant.SharedPreferenceConstants.KEY_QUICK_SEND
import org.mariotaku.twidere.extension.applyTheme import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.model.AccountDetails import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.ParcelableStatusUpdate
import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.service.LengthyOperationsService import org.mariotaku.twidere.service.LengthyOperationsService
import org.mariotaku.twidere.util.Analyzer import org.mariotaku.twidere.util.Analyzer
@ -62,9 +61,9 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context) val builder = AlertDialog.Builder(context)
val context = builder.context val status = this.status
val status = status!! val accountKey = this.accountKey
val details = AccountUtils.getAccountDetails(AccountManager.get(context), status.account_key, true)!! val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)!!
builder.setView(R.layout.dialog_status_quote_retweet) builder.setView(R.layout.dialog_status_quote_retweet)
builder.setTitle(R.string.retweet_quote_confirm_title) builder.setTitle(R.string.retweet_quote_confirm_title)
@ -104,7 +103,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
val useQuote = useQuote(!status.user_is_protected, details) val useQuote = useQuote(!status.user_is_protected, details)
commentContainer.visibility = if (useQuote) View.VISIBLE else View.GONE commentContainer.visibility = if (useQuote) View.VISIBLE else View.GONE
editComment.accountKey = (status.account_key) editComment.accountKey = details.key
val sendByEnter = preferences.getBoolean(KEY_QUICK_SEND) val sendByEnter = preferences.getBoolean(KEY_QUICK_SEND)
val enterHandler = EditTextEnterHandler.attach(editComment, object : EditTextEnterHandler.EnterListener { val enterHandler = EditTextEnterHandler.attach(editComment, object : EditTextEnterHandler.EnterListener {
@ -155,7 +154,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
if (editComment.length() > 0) { if (editComment.length() > 0) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM) dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else if (isMyRetweet(status)) { } else if (isMyRetweet(status)) {
twitterWrapper.cancelRetweetAsync(status.account_key, status.id, status.my_retweet_id) twitterWrapper.cancelRetweetAsync(details.key, status.id, status.my_retweet_id)
dismissDialog = true dismissDialog = true
} else if (useQuote(!status.user_is_protected, details)) { } else if (useQuote(!status.user_is_protected, details)) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM) dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
@ -192,12 +191,11 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
textCountView.textCount = validator.getTweetLength(s.toString()) textCountView.textCount = validator.getTweetLength(s.toString())
} }
private val status: ParcelableStatus? private val status: ParcelableStatus
get() { get() = arguments.getParcelable<ParcelableStatus>(EXTRA_STATUS)
val args = arguments
if (!args.containsKey(EXTRA_STATUS)) return null private val accountKey: UserKey
return args.getParcelable<ParcelableStatus>(EXTRA_STATUS) get() = arguments.getParcelable(EXTRA_ACCOUNT_KEY) ?: status.account_key
}
@CheckResult @CheckResult
private fun retweetOrQuote(account: AccountDetails, status: ParcelableStatus, private fun retweetOrQuote(account: AccountDetails, status: ParcelableStatus,
@ -252,7 +250,7 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
update.is_possibly_sensitive = status.is_possibly_sensitive update.is_possibly_sensitive = status.is_possibly_sensitive
LengthyOperationsService.updateStatusesAsync(context, Draft.Action.QUOTE, update) LengthyOperationsService.updateStatusesAsync(context, Draft.Action.QUOTE, update)
} else { } else {
twitter.retweetStatusAsync(status.account_key, status) twitter.retweetStatusAsync(account.key, status)
} }
return true return true
} }
@ -314,11 +312,12 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
val FRAGMENT_TAG = "retweet_quote" val FRAGMENT_TAG = "retweet_quote"
private val SHOW_PROTECTED_CONFIRM = java.lang.Boolean.parseBoolean("false") private val SHOW_PROTECTED_CONFIRM = java.lang.Boolean.parseBoolean("false")
fun show(fm: FragmentManager, status: ParcelableStatus): RetweetQuoteDialogFragment { fun show(fm: FragmentManager, status: ParcelableStatus, accountKey: UserKey? = null): RetweetQuoteDialogFragment {
val args = Bundle()
args.putParcelable(EXTRA_STATUS, status)
val f = RetweetQuoteDialogFragment() val f = RetweetQuoteDialogFragment()
f.arguments = args f.arguments = Bundle {
this[EXTRA_STATUS] = status
this[EXTRA_ACCOUNT_KEY] = accountKey
}
f.show(fm, FRAGMENT_TAG) f.show(fm, FRAGMENT_TAG)
return f return f
} }

View File

@ -33,7 +33,6 @@ import android.os.Bundle
import android.support.annotation.UiThread import android.support.annotation.UiThread
import android.support.v4.app.LoaderManager.LoaderCallbacks import android.support.v4.app.LoaderManager.LoaderCallbacks
import android.support.v4.app.hasRunningLoadersSafe import android.support.v4.app.hasRunningLoadersSafe
import android.support.v4.content.AsyncTaskLoader
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
import android.support.v4.content.FixedAsyncTaskLoader import android.support.v4.content.FixedAsyncTaskLoader
import android.support.v4.content.Loader import android.support.v4.content.Loader
@ -98,8 +97,6 @@ import org.mariotaku.twidere.loader.ConversationLoader
import org.mariotaku.twidere.loader.ParcelableStatusLoader import org.mariotaku.twidere.loader.ParcelableStatusLoader
import org.mariotaku.twidere.menu.FavoriteItemProvider import org.mariotaku.twidere.menu.FavoriteItemProvider
import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableStatusValuesCreator
import org.mariotaku.twidere.model.ParcelableActivityCursorIndices
import org.mariotaku.twidere.model.analyzer.Share import org.mariotaku.twidere.model.analyzer.Share
import org.mariotaku.twidere.model.analyzer.StatusView import org.mariotaku.twidere.model.analyzer.StatusView
import org.mariotaku.twidere.model.message.FavoriteTaskEvent import org.mariotaku.twidere.model.message.FavoriteTaskEvent
@ -259,6 +256,10 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
IntentUtils.openStatus(activity, accountKey, status.id) IntentUtils.openStatus(activity, accountKey, status.id)
} }
} }
AbsStatusesFragment.REQUEST_FAVORITE_SELECT_ACCOUNT,
AbsStatusesFragment.REQUEST_RETWEET_SELECT_ACCOUNT -> {
AbsStatusesFragment.handleActionActivityResult(this, requestCode, resultCode, data)
}
} }
} }
@ -310,11 +311,17 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
} }
override fun onItemActionClick(holder: ViewHolder, id: Int, position: Int) { override fun onItemActionClick(holder: ViewHolder, id: Int, position: Int) {
val status = adapter.getStatus(position) val status = adapter.getStatus(position) ?: return
AbsStatusesFragment.handleStatusActionClick(context, fragmentManager, twitterWrapper, AbsStatusesFragment.handleActionClick(context, fragmentManager, twitterWrapper,
holder as StatusViewHolder, status, id) holder as StatusViewHolder, status, id)
} }
override fun onItemActionLongClick(holder: RecyclerView.ViewHolder, id: Int, position: Int): Boolean {
val status = adapter.getStatus(position) ?: return false
return AbsStatusesFragment.handleActionLongClick(this, status, adapter.getItemId(position), id)
}
override fun onStatusClick(holder: IStatusViewHolder, position: Int) { override fun onStatusClick(holder: IStatusViewHolder, position: Int) {
val status = adapter.getStatus(position) ?: return val status = adapter.getStatus(position) ?: return
IntentUtils.openStatus(activity, status) IntentUtils.openStatus(activity, status)
@ -339,15 +346,14 @@ class StatusFragment : BaseFragment(), LoaderCallbacks<SingleResponse<Parcelable
override fun onUserProfileClick(holder: IStatusViewHolder, position: Int) { override fun onUserProfileClick(holder: IStatusViewHolder, position: Int) {
val status = adapter.getStatus(position)!! val status = adapter.getStatus(position)!!
IntentUtils.openUserProfile(activity, status.account_key, status.user_key, IntentUtils.openUserProfile(activity, status.account_key, status.user_key,
status.user_screen_name, preferences.getBoolean(KEY_NEW_DOCUMENT_API), Referral.TIMELINE_STATUS, status.user_screen_name, preferences[newDocumentApiKey], Referral.TIMELINE_STATUS,
null) null)
} }
override fun onMediaClick(view: View, media: ParcelableMedia, accountKey: UserKey?, id: Long) { override fun onMediaClick(view: View, media: ParcelableMedia, accountKey: UserKey?, id: Long) {
val status = adapter.status val status = adapter.status ?: return
if (status == null || media == null) return IntentUtils.openMediaDirectly(activity, accountKey, status, media,
IntentUtils.openMediaDirectly(activity, accountKey, status, media, preferences.getBoolean(KEY_NEW_DOCUMENT_API), preferences[newDocumentApiKey], null)
null)
// BEGIN HotMobi // BEGIN HotMobi
val event = MediaEvent.create(activity, status, media, TimelineType.OTHER, val event = MediaEvent.create(activity, status, media, TimelineType.OTHER,
adapter.mediaPreviewEnabled) adapter.mediaPreviewEnabled)

View File

@ -105,7 +105,7 @@ class ExtensionsListLoader(
val label: String val label: String
val description: String val description: String
val pname: String val pname: String
val settings: String val settings: String?
val icon: Drawable val icon: Drawable
init { init {

View File

@ -1,11 +1,14 @@
package org.mariotaku.twidere.model.analyzer package org.mariotaku.twidere.model.analyzer
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.extension.model.draftActionTypeString import org.mariotaku.twidere.extension.model.draftActionTypeString
import org.mariotaku.twidere.extension.model.parcelableMediaTypeString import org.mariotaku.twidere.extension.model.parcelableMediaTypeString
import org.mariotaku.twidere.model.Draft import org.mariotaku.twidere.model.Draft
import org.mariotaku.twidere.model.ParcelableMedia import org.mariotaku.twidere.model.ParcelableMedia
import org.mariotaku.twidere.task.twitter.UpdateStatusTask
import org.mariotaku.twidere.util.Analyzer import org.mariotaku.twidere.util.Analyzer
import java.io.IOException
/** /**
* Created by mariotaku on 2016/12/28. * Created by mariotaku on 2016/12/28.
@ -17,7 +20,8 @@ data class UpdateStatus(
@ParcelableMedia.Type val mediaType: Int, @ParcelableMedia.Type val mediaType: Int,
val hasLocation: Boolean, val hasLocation: Boolean,
val preciseLocation: Boolean, val preciseLocation: Boolean,
val success: Boolean val success: Boolean,
val exception: Exception?
) : Analyzer.Event { ) : Analyzer.Event {
private val locationType: String get() = if (!hasLocation) { private val locationType: String get() = if (!hasLocation) {
@ -28,6 +32,36 @@ data class UpdateStatus(
"place" "place"
} }
private val errorReason: String? get() {
val ex = exception ?: return null
when (ex) {
is UpdateStatusTask.ShortenerNotFoundException,
is UpdateStatusTask.UploaderNotFoundException ->
return "extension not found"
else -> {
val cause = ex.cause
when (cause) {
is UpdateStatusTask.ExtensionVersionMismatchException ->
return "extension version mismatch"
is IOException ->
return "io exception"
is MicroBlogException -> {
if (cause.isCausedByNetworkIssue) {
return "network error"
}
return "request error"
}
}
when (ex) {
is UpdateStatusTask.ShortenException,
is UpdateStatusTask.UploadException ->
return "extension error"
}
return "internal error"
}
}
}
override val name: String override val name: String
get() = "Tweet" get() = "Tweet"
@ -36,6 +70,7 @@ data class UpdateStatus(
action("Media Type", parcelableMediaTypeString(mediaType)) action("Media Type", parcelableMediaTypeString(mediaType))
action("Location Type", locationType) action("Location Type", locationType)
action("Success", success.toString()) action("Success", success.toString())
} }
} }

View File

@ -378,11 +378,11 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
Utils.setLastSeen(this, UserKey(recipientId, accountKey.host), Utils.setLastSeen(this, UserKey(recipientId, accountKey.host),
System.currentTimeMillis()) System.currentTimeMillis())
return SingleResponse.getInstance(directMessage) return SingleResponse(directMessage)
} catch (e: IOException) { } catch (e: IOException) {
return SingleResponse.getInstance<ParcelableDirectMessage>(e) return SingleResponse(e)
} catch (e: MicroBlogException) { } catch (e: MicroBlogException) {
return SingleResponse.getInstance<ParcelableDirectMessage>(e) return SingleResponse(e)
} }
} }

View File

@ -94,7 +94,7 @@ class UpdateStatusTask(
val hasLocation = statusUpdate.location != null val hasLocation = statusUpdate.location != null
val preciseLocation = statusUpdate.display_coordinates val preciseLocation = statusUpdate.display_coordinates
Analyzer.log(UpdateStatus(result.accountTypes.firstOrNull(), actionType, mediaType, Analyzer.log(UpdateStatus(result.accountTypes.firstOrNull(), actionType, mediaType,
hasLocation, preciseLocation, result.succeed)) hasLocation, preciseLocation, result.succeed, result.exceptions.firstOrNull() ?: result.exception))
} }
@Throws(UpdateStatusException::class) @Throws(UpdateStatusException::class)
@ -110,11 +110,7 @@ class UpdateStatusTask(
uploadMedia(uploader, update, pendingUpdate) uploadMedia(uploader, update, pendingUpdate)
shortenStatus(shortener, update, pendingUpdate) shortenStatus(shortener, update, pendingUpdate)
try { result = requestUpdateStatus(update, pendingUpdate, draftId)
result = requestUpdateStatus(update, pendingUpdate, draftId)
} catch (e: IOException) {
return UpdateStatusResult(UpdateStatusException(e), draftId)
}
mediaUploadCallback(uploader, pendingUpdate, result) mediaUploadCallback(uploader, pendingUpdate, result)
statusShortenCallback(shortener, pendingUpdate, result) statusShortenCallback(shortener, pendingUpdate, result)
@ -240,10 +236,12 @@ class UpdateStatusTask(
} }
} }
@Throws(IOException::class) @Throws(UpdateStatusException::class)
private fun requestUpdateStatus(statusUpdate: ParcelableStatusUpdate, private fun requestUpdateStatus(
pendingUpdate: PendingStatusUpdate, statusUpdate: ParcelableStatusUpdate,
draftId: Long): UpdateStatusResult { pendingUpdate: PendingStatusUpdate,
draftId: Long
): UpdateStatusResult {
stateCallback.onUpdatingStatus() stateCallback.onUpdatingStatus()
@ -253,55 +251,54 @@ class UpdateStatusTask(
val account = statusUpdate.accounts[i] val account = statusUpdate.accounts[i]
result.accountTypes[i] = account.type result.accountTypes[i] = account.type
val microBlog = MicroBlogAPIFactory.getInstance(context, account.key) val microBlog = MicroBlogAPIFactory.getInstance(context, account.key)
var mediaBody: MediaStreamBody? = null
try { try {
when (account.type) { val requestResult = when (account.type) {
AccountType.FANFOU -> { AccountType.FANFOU -> {
// Call uploadPhoto if media present // Call uploadPhoto if media present
if (!ArrayUtils.isEmpty(statusUpdate.media)) { if (statusUpdate.media.isNotNullOrEmpty()) {
// Fanfou only allow one photo // Fanfou only allow one photo
if (statusUpdate.media.size > 1) { fanfouUpdateStatusWithPhoto(microBlog, statusUpdate, pendingUpdate,
result.exceptions[i] = MicroBlogException( pendingUpdate.overrideTexts[i], account.size_limit, i)
context.getString(R.string.error_too_many_photos_fanfou))
} else {
val sizeLimit = account.size_limit
val firstMedia = statusUpdate.media.first()
mediaBody = getBodyFromMedia(context, mediaLoader, Uri.parse(firstMedia.uri),
sizeLimit, firstMedia.type, false, ContentLengthInputStream.ReadListener { length, position ->
stateCallback.onUploadingProgressChanged(-1, position, length)
})
val photoUpdate = PhotoStatusUpdate(mediaBody.body,
pendingUpdate.overrideTexts[i])
val requestResult = microBlog.uploadPhoto(photoUpdate)
result.statuses[i] = ParcelableStatusUtils.fromStatus(requestResult,
account.key, false)
}
} else { } else {
val requestResult = twitterUpdateStatus(microBlog, statusUpdate, twitterUpdateStatus(microBlog, statusUpdate, pendingUpdate,
pendingUpdate, pendingUpdate.overrideTexts[i], i) pendingUpdate.overrideTexts[i], i)
result.statuses[i] = ParcelableStatusUtils.fromStatus(requestResult,
account.key, false)
} }
} }
else -> { else -> {
val requestResult = twitterUpdateStatus(microBlog, statusUpdate, twitterUpdateStatus(microBlog, statusUpdate, pendingUpdate,
pendingUpdate, pendingUpdate.overrideTexts[i], i) pendingUpdate.overrideTexts[i], i)
result.statuses[i] = ParcelableStatusUtils.fromStatus(requestResult,
account.key, false)
} }
} }
result.statuses[i] = ParcelableStatusUtils.fromStatus(requestResult,
account.key, false)
} catch (e: MicroBlogException) { } catch (e: MicroBlogException) {
result.exceptions[i] = e result.exceptions[i] = e
} finally {
Utils.closeSilently(mediaBody)
} }
} }
return result return result
} }
@Throws(MicroBlogException::class, UploadException::class)
private fun fanfouUpdateStatusWithPhoto(microBlog: MicroBlog, statusUpdate: ParcelableStatusUpdate,
pendingUpdate: PendingStatusUpdate, overrideText: String,
sizeLimit: SizeLimit, updateIndex: Int): Status {
if (statusUpdate.media.size > 1) {
throw MicroBlogException(context.getString(R.string.error_too_many_photos_fanfou))
}
val media = statusUpdate.media.first()
try {
return getBodyFromMedia(context, mediaLoader, Uri.parse(media.uri), sizeLimit, media.type,
false, ContentLengthInputStream.ReadListener { length, position ->
stateCallback.onUploadingProgressChanged(-1, position, length)
}).use { mediaBody ->
val photoUpdate = PhotoStatusUpdate(mediaBody.body, pendingUpdate.overrideTexts[updateIndex])
return@use microBlog.uploadPhoto(photoUpdate)
}
} catch (e: IOException) {
throw UploadException(e)
}
}
/** /**
* Calling Twitter's upload method. This method sets multiple owner for bandwidth saving * Calling Twitter's upload method. This method sets multiple owner for bandwidth saving
*/ */
@ -439,7 +436,7 @@ class UpdateStatusTask(
} }
} catch (e: AbsServiceInterface.CheckServiceException) { } catch (e: AbsServiceInterface.CheckServiceException) {
if (e is ExtensionVersionMismatchException) { if (e is ExtensionVersionMismatchException) {
throw UploadException(context.getString(R.string.uploader_version_incompatible)) throw UploadException(context.getString(R.string.uploader_version_incompatible), e)
} }
throw UploadException(e) throw UploadException(e)
} }
@ -622,25 +619,16 @@ class UpdateStatusTask(
open class UpdateStatusException : Exception { open class UpdateStatusException : Exception {
constructor() : super() protected constructor() : super()
constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable) protected constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable)
constructor(throwable: Throwable) : super(throwable) protected constructor(throwable: Throwable) : super(throwable)
constructor(message: String) : super(message) protected constructor(message: String) : super(message)
} }
class UploaderNotFoundException : UpdateStatusException { class UploaderNotFoundException(message: String) : UpdateStatusException(message)
constructor() : super()
constructor(detailMessage: String, throwable: Throwable) : super(detailMessage, throwable)
constructor(throwable: Throwable) : super(throwable)
constructor(message: String) : super(message)
}
class UploadException : UpdateStatusException { class UploadException : UpdateStatusException {

View File

@ -11,7 +11,6 @@ import android.view.View.OnLongClickListener
import android.widget.ImageView import android.widget.ImageView
import kotlinx.android.synthetic.main.list_item_status.view.* import kotlinx.android.synthetic.main.list_item_status.view.*
import org.mariotaku.ktextension.applyFontFamily import org.mariotaku.ktextension.applyFontFamily
import org.mariotaku.twidere.Constants
import org.mariotaku.twidere.Constants.* import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM import org.mariotaku.twidere.TwidereConstants.USER_TYPE_FANFOU_COM
@ -40,7 +39,7 @@ import java.lang.ref.WeakReference
* *
* Created by mariotaku on 14/11/19. * Created by mariotaku on 14/11/19.
*/ */
class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) : ViewHolder(itemView), Constants, IStatusViewHolder { class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View) : ViewHolder(itemView), IStatusViewHolder {
override val profileImageView: ProfileImageView by lazy { itemView.profileImage } override val profileImageView: ProfileImageView by lazy { itemView.profileImage }
override val profileTypeView: ImageView by lazy { itemView.profileType } override val profileTypeView: ImageView by lazy { itemView.profileType }
@ -463,6 +462,8 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
replyButton.setOnClickListener(eventListener) replyButton.setOnClickListener(eventListener)
retweetButton.setOnClickListener(eventListener) retweetButton.setOnClickListener(eventListener)
favoriteButton.setOnClickListener(eventListener) favoriteButton.setOnClickListener(eventListener)
retweetButton.setOnLongClickListener(eventListener)
favoriteButton.setOnLongClickListener(eventListener)
mediaLabel.setOnClickListener(eventListener) mediaLabel.setOnClickListener(eventListener)
@ -648,6 +649,12 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
} }
return listener.onStatusLongClick(holder, position) return listener.onStatusLongClick(holder, position)
} }
holder.favoriteButton -> {
return listener.onItemActionLongClick(holder, R.id.favorite, position)
}
holder.retweetButton -> {
return listener.onItemActionLongClick(holder, R.id.retweet, position)
}
} }
return false return false
} }