implemented twitter retweet/favorite intent handling

This commit is contained in:
Mariotaku Lee 2017-04-12 19:25:10 +08:00
parent f1bafacfd4
commit fbaf4dd0da
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
11 changed files with 415 additions and 247 deletions

View File

@ -1 +1 @@
e996a88227d4a77ebe6739b7286d744f2023e398 ea793d047ce90d44b4d0d8b67cb69c0b99ca173e

View File

@ -8,6 +8,8 @@ import android.text.TextUtils
import org.mariotaku.ktextension.toLongOr import org.mariotaku.ktextension.toLongOr
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.content.FavoriteConfirmDialogActivity
import org.mariotaku.twidere.activity.content.RetweetQuoteDialogActivity
import org.mariotaku.twidere.app.TwidereApplication import org.mariotaku.twidere.app.TwidereApplication
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.util.Analyzer import org.mariotaku.twidere.util.Analyzer
@ -276,14 +278,27 @@ class WebLinkHandlerActivity : Activity() {
handledIntent.putExtra(Intent.EXTRA_TEXT, sb.toString()) handledIntent.putExtra(Intent.EXTRA_TEXT, sb.toString())
return Pair(handledIntent, true) return Pair(handledIntent, true)
} }
"favorite", "retweet" -> { "retweet" -> {
val tweetId = uri.getQueryParameter("tweet_id") ?: return Pair(null, false) val tweetId = uri.getQueryParameter("tweet_id") ?: return Pair(null, false)
return Pair(IntentUtils.status(null, tweetId), true) val accountHost = USER_TYPE_TWITTER_COM
val intent = Intent(this, RetweetQuoteDialogActivity::class.java)
intent.putExtra(EXTRA_STATUS_ID, tweetId)
intent.putExtra(EXTRA_ACCOUNT_HOST, accountHost)
return Pair(intent, true)
}
"favorite", "like" -> {
val tweetId = uri.getQueryParameter("tweet_id") ?: return Pair(null, false)
val accountHost = USER_TYPE_TWITTER_COM
val intent = Intent(this, FavoriteConfirmDialogActivity::class.java)
intent.putExtra(EXTRA_STATUS_ID, tweetId)
intent.putExtra(EXTRA_ACCOUNT_HOST, accountHost)
return Pair(intent, true)
} }
"user", "follow" -> { "user", "follow" -> {
val userKey = uri.getQueryParameter("user_id")?.let { UserKey(it, "twitter.com") } val userKey = uri.getQueryParameter("user_id")?.let { UserKey(it, "twitter.com") }
val screenName = uri.getQueryParameter("screen_name") val screenName = uri.getQueryParameter("screen_name")
return Pair(IntentUtils.userProfile(null, userKey, screenName), true) return Pair(IntentUtils.userProfile(null, userKey, screenName,
accountHost = USER_TYPE_TWITTER_COM), true)
} }
} }
return Pair(null, false) return Pair(null, false)

View File

@ -0,0 +1,76 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 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.activity.content
import android.content.Intent
import android.os.Bundle
import org.mariotaku.twidere.TwidereConstants.REQUEST_SELECT_ACCOUNT
import org.mariotaku.twidere.activity.AccountSelectorActivity
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
abstract class AbsStatusDialogActivity : BaseActivity() {
private val statusId: String
get() = intent.getStringExtra(EXTRA_STATUS_ID)
private val accountKey: UserKey?
get() = intent.getParcelableExtra(EXTRA_ACCOUNT_KEY)
private val accountHost: String?
get() = intent.getStringExtra(EXTRA_ACCOUNT_HOST)
private val status: ParcelableStatus?
get() = intent.getParcelableExtra(EXTRA_STATUS)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
val accountKey = this.accountKey
if (accountKey != null) {
showDialogFragment(accountKey, statusId, status)
} else {
val intent = Intent(this, AccountSelectorActivity::class.java)
intent.putExtra(EXTRA_SINGLE_SELECTION, true)
intent.putExtra(EXTRA_SELECT_ONLY_ITEM_AUTOMATICALLY, true)
intent.putExtra(EXTRA_ACCOUNT_HOST, accountHost)
startActivityForResult(intent, REQUEST_SELECT_ACCOUNT)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_SELECT_ACCOUNT -> {
if (resultCode == RESULT_OK && data != null) {
val accountKey = data.getParcelableExtra<UserKey>(EXTRA_ACCOUNT_KEY)
showDialogFragment(accountKey, statusId, status)
return
}
}
}
finish()
}
protected abstract fun showDialogFragment(accountKey: UserKey, statusId: String,
status: ParcelableStatus?)
}

View File

@ -19,9 +19,6 @@
package org.mariotaku.twidere.activity.content package org.mariotaku.twidere.activity.content
import android.os.Bundle
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.fragment.content.FavoriteConfirmDialogFragment import org.mariotaku.twidere.fragment.content.FavoriteConfirmDialogFragment
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
@ -31,21 +28,12 @@ import org.mariotaku.twidere.model.UserKey
* *
* Created by mariotaku on 2017/4/12. * Created by mariotaku on 2017/4/12.
*/ */
class FavoriteConfirmDialogActivity : BaseActivity() { class FavoriteConfirmDialogActivity : AbsStatusDialogActivity() {
private val status: ParcelableStatus override fun showDialogFragment(accountKey: UserKey, statusId: String, status: ParcelableStatus?) {
get() = intent.getParcelableExtra(EXTRA_STATUS) executeAfterFragmentResumed {
FavoriteConfirmDialogFragment.show(it.supportFragmentManager, accountKey, statusId, status)
private val statusId: String
get() = intent.getStringExtra(EXTRA_STATUS_ID)
private val accountKey: UserKey?
get() = intent.getParcelableExtra(EXTRA_ACCOUNT_KEY)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
FavoriteConfirmDialogFragment.show(supportFragmentManager, accountKey, statusId, status)
} }
} }
} }

View File

@ -19,9 +19,7 @@
package org.mariotaku.twidere.activity.content package org.mariotaku.twidere.activity.content
import android.os.Bundle import org.mariotaku.twidere.constant.IntentConstants.EXTRA_TEXT
import org.mariotaku.twidere.activity.BaseActivity
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.fragment.content.RetweetQuoteDialogFragment import org.mariotaku.twidere.fragment.content.RetweetQuoteDialogFragment
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
@ -31,25 +29,17 @@ import org.mariotaku.twidere.model.UserKey
* *
* Created by mariotaku on 2017/4/8. * Created by mariotaku on 2017/4/8.
*/ */
class RetweetQuoteDialogActivity : BaseActivity() { class RetweetQuoteDialogActivity : AbsStatusDialogActivity() {
private val status: ParcelableStatus
get() = intent.getParcelableExtra(EXTRA_STATUS)
private val statusId: String
get() = intent.getStringExtra(EXTRA_STATUS_ID)
private val accountKey: UserKey?
get() = intent.getParcelableExtra(EXTRA_ACCOUNT_KEY)
private val text: String? private val text: String?
get() = intent.getStringExtra(EXTRA_TEXT) get() = intent.getStringExtra(EXTRA_TEXT)
override fun onCreate(savedInstanceState: Bundle?) { override fun showDialogFragment(accountKey: UserKey, statusId: String, status: ParcelableStatus?) {
super.onCreate(savedInstanceState) val text = this.text
if (savedInstanceState == null) { executeAfterFragmentResumed {
RetweetQuoteDialogFragment.show(supportFragmentManager, accountKey, statusId, status, RetweetQuoteDialogFragment.show(it.supportFragmentManager, accountKey, statusId,
text) status, text)
} }
} }
} }

View File

@ -0,0 +1,145 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2017 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.content
import android.accounts.AccountManager
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.os.Bundle
import android.support.v7.app.AlertDialog
import android.view.View
import android.widget.Toast
import com.bumptech.glide.Glide
import kotlinx.android.synthetic.main.list_item_status.view.*
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.combine.and
import nl.komponents.kovenant.task
import nl.komponents.kovenant.ui.failUi
import nl.komponents.kovenant.ui.promiseOnUi
import nl.komponents.kovenant.ui.successUi
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.DummyItemAdapter
import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.extension.applyTheme
import org.mariotaku.twidere.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.model.util.ParcelableStatusUtils
import org.mariotaku.twidere.view.holder.StatusViewHolder
import java.lang.ref.WeakReference
abstract class AbsStatusDialogFragment : BaseDialogFragment() {
protected abstract val Dialog.loadProgress: View
protected abstract val Dialog.itemContent: View
protected val status: ParcelableStatus?
get() = arguments.getParcelable<ParcelableStatus>(EXTRA_STATUS)
protected val statusId: String
get() = arguments.getString(EXTRA_STATUS_ID)
protected val accountKey: UserKey
get() = arguments.getParcelable(EXTRA_ACCOUNT_KEY)
override final fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
val accountKey = this.accountKey
builder.setupAlertDialog()
val dialog = builder.create()
dialog.setOnShowListener { dialog ->
dialog as AlertDialog
dialog.applyTheme()
val am = AccountManager.get(context)
val details = AccountUtils.getAccountDetails(am, accountKey, true) ?: run {
dismiss()
return@setOnShowListener
}
val weakThis = WeakReference(this)
promiseOnUi {
val currentDialog = weakThis.get()?.dialog as? AlertDialog ?: return@promiseOnUi
currentDialog.loadProgress.visibility = View.VISIBLE
currentDialog.itemContent.visibility = View.GONE
currentDialog.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = false
currentDialog.getButton(DialogInterface.BUTTON_NEUTRAL)?.isEnabled = false
} and showStatus(context, details, statusId, status).successUi { status ->
val fragment = weakThis.get() ?: return@successUi
val currentDialog = fragment.dialog as? AlertDialog ?: return@successUi
currentDialog.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = true
currentDialog.getButton(DialogInterface.BUTTON_NEUTRAL)?.isEnabled = true
currentDialog.itemContent.visibility = View.VISIBLE
currentDialog.loadProgress.visibility = View.GONE
currentDialog.itemContent.isFocusable = false
currentDialog.itemContent.itemMenu.visibility = View.GONE
currentDialog.itemContent.actionButtons.visibility = View.GONE
val adapter = DummyItemAdapter(fragment.context, requestManager = Glide.with(fragment))
adapter.setShouldShowAccountsColor(true)
val holder = StatusViewHolder(adapter, currentDialog.itemContent)
holder.displayStatus(status = status, displayInReplyTo = false)
currentDialog.onStatusLoaded(details, status, savedInstanceState)
}.failUi {
val fragment = weakThis.get()?.takeIf { it.dialog != null } ?: return@failUi
Toast.makeText(fragment.context, R.string.message_toast_error_occurred, Toast.LENGTH_SHORT).show()
fragment.dismiss()
}
}
return dialog
}
protected abstract fun AlertDialog.Builder.setupAlertDialog()
protected abstract fun AlertDialog.onStatusLoaded(details: AccountDetails, status: ParcelableStatus,
savedInstanceState: Bundle?)
companion object {
fun showStatus(context: Context, details: AccountDetails, statusId: String,
status: ParcelableStatus?): Promise<ParcelableStatus, Exception> {
if (status != null) {
status.apply {
if (account_key != details.key) {
my_retweet_id = null
is_favorite = false
}
account_key = details.key
account_color = details.color
}
return Promise.ofSuccess(status)
}
val microBlog = details.newMicroBlogInstance(context, MicroBlog::class.java)
val profileImageSize = context.getString(R.string.profile_image_size)
return task {
val status = ParcelableStatusUtils.fromStatus(microBlog.showStatus(statusId),
details.key, details.type, profileImageSize = profileImageSize)
status.account_color = details.color
return@task status
}
}
}
}

View File

@ -19,111 +19,66 @@
package org.mariotaku.twidere.fragment.content package org.mariotaku.twidere.fragment.content
import android.accounts.AccountManager
import android.app.Dialog import android.app.Dialog
import android.content.DialogInterface import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.view.View import android.view.View
import android.widget.ImageButton
import android.widget.LinearLayout
import com.bumptech.glide.Glide
import org.mariotaku.kpreferences.get import org.mariotaku.kpreferences.get
import org.mariotaku.ktextension.Bundle import org.mariotaku.ktextension.Bundle
import org.mariotaku.ktextension.set import org.mariotaku.ktextension.set
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.content.RetweetQuoteDialogActivity import org.mariotaku.twidere.activity.content.FavoriteConfirmDialogActivity
import org.mariotaku.twidere.adapter.DummyItemAdapter
import org.mariotaku.twidere.constant.IntentConstants.* import org.mariotaku.twidere.constant.IntentConstants.*
import org.mariotaku.twidere.constant.iWantMyStarsBackKey import org.mariotaku.twidere.constant.iWantMyStarsBackKey
import org.mariotaku.twidere.extension.applyTheme import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.model.ParcelableStatus import org.mariotaku.twidere.model.ParcelableStatus
import org.mariotaku.twidere.model.UserKey import org.mariotaku.twidere.model.UserKey
import org.mariotaku.twidere.model.util.AccountUtils
import org.mariotaku.twidere.view.ColorLabelRelativeLayout
import org.mariotaku.twidere.view.holder.StatusViewHolder
/** /**
* Asks user to favorite a status. * Asks user to favorite a status.
* *
* Created by mariotaku on 2017/4/12. * Created by mariotaku on 2017/4/12.
*/ */
class FavoriteConfirmDialogFragment : BaseDialogFragment() { class FavoriteConfirmDialogFragment : AbsStatusDialogFragment() {
private val Dialog.loadProgress get() = findViewById(R.id.loadProgress) override val Dialog.loadProgress: View get() = findViewById(R.id.loadProgress)
private val Dialog.itemContent get() = findViewById(R.id.itemContent) as ColorLabelRelativeLayout
private val Dialog.itemMenu get() = findViewById(R.id.itemMenu) as ImageButton
private val Dialog.actionButtons get() = findViewById(R.id.actionButtons) as LinearLayout
private val status: ParcelableStatus override val Dialog.itemContent: View get() = findViewById(R.id.itemContent)
get() = arguments.getParcelable<ParcelableStatus>(EXTRA_STATUS)
private val accountKey: UserKey override fun AlertDialog.Builder.setupAlertDialog() {
get() = arguments.getParcelable(EXTRA_ACCOUNT_KEY) ?: status.account_key setTitle(R.string.title_favorite_confirm)
setView(R.layout.dialog_status_favorite_confirm)
setPositiveButton(R.string.action_favorite, null)
setNegativeButton(android.R.string.cancel, null)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun AlertDialog.onStatusLoaded(details: AccountDetails, status: ParcelableStatus,
val builder = AlertDialog.Builder(context) savedInstanceState: Bundle?) {
val accountKey = this.accountKey val positiveButton = getButton(DialogInterface.BUTTON_POSITIVE)
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)!!
val status = this.status.apply {
if (account_key != accountKey) {
is_favorite = false
}
account_key = details.key
account_color = details.color
}
builder.setView(R.layout.dialog_status_favorite_confirm)
builder.setTitle(R.string.title_favorite_confirm)
if (preferences[iWantMyStarsBackKey]) { if (preferences[iWantMyStarsBackKey]) {
builder.setPositiveButton(R.string.action_favorite, null) if (status.is_favorite) {
} else { positiveButton.setText(R.string.action_unfavorite)
builder.setPositiveButton(R.string.action_like, null)
}
builder.setNegativeButton(android.R.string.cancel, null)
val dialog = builder.create()
dialog.setOnShowListener { dialog ->
dialog as AlertDialog
dialog.applyTheme()
val adapter = DummyItemAdapter(context, requestManager = Glide.with(this))
adapter.setShouldShowAccountsColor(true)
val holder = StatusViewHolder(adapter, dialog.itemContent)
holder.displayStatus(status = status, displayInReplyTo = false)
dialog.loadProgress.visibility = View.GONE
dialog.itemMenu.visibility = View.GONE
dialog.actionButtons.visibility = View.GONE
dialog.itemContent.isFocusable = false
val positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
if (preferences[iWantMyStarsBackKey]) {
if (status.is_favorite) {
positiveButton.setText(R.string.action_unfavorite)
} else {
positiveButton.setText(R.string.action_favorite)
}
} else { } else {
if (status.is_favorite) { positiveButton.setText(R.string.action_favorite)
positiveButton.setText(R.string.action_undo_like)
} else {
positiveButton.setText(R.string.action_like)
}
} }
positiveButton.setOnClickListener { } else {
if (status.is_favorite) { if (status.is_favorite) {
twitterWrapper.destroyFavoriteAsync(accountKey, status.id) positiveButton.setText(R.string.action_undo_like)
} else { } else {
twitterWrapper.createFavoriteAsync(accountKey, status) positiveButton.setText(R.string.action_like)
}
dismiss()
} }
} }
return dialog positiveButton.setOnClickListener {
if (status.is_favorite) {
twitterWrapper.destroyFavoriteAsync(accountKey, status.id)
} else {
twitterWrapper.createFavoriteAsync(accountKey, status)
}
dismiss()
}
} }
override fun onCancel(dialog: DialogInterface) { override fun onCancel(dialog: DialogInterface) {
@ -137,7 +92,7 @@ class FavoriteConfirmDialogFragment : BaseDialogFragment() {
private fun finishFavoriteConfirmActivity() { private fun finishFavoriteConfirmActivity() {
val activity = this.activity val activity = this.activity
if (activity is RetweetQuoteDialogActivity && !activity.isFinishing) { if (activity is FavoriteConfirmDialogActivity && !activity.isFinishing) {
activity.finish() activity.finish()
} }
} }
@ -146,8 +101,8 @@ class FavoriteConfirmDialogFragment : BaseDialogFragment() {
val FRAGMENT_TAG = "favorite_confirm" val FRAGMENT_TAG = "favorite_confirm"
fun show(fm: FragmentManager, accountKey: UserKey? = null, statusId: String, fun show(fm: FragmentManager, accountKey: UserKey, statusId: String,
status: ParcelableStatus?): FavoriteConfirmDialogFragment { status: ParcelableStatus? = null): FavoriteConfirmDialogFragment {
val f = FavoriteConfirmDialogFragment() val f = FavoriteConfirmDialogFragment()
f.arguments = Bundle { f.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey this[EXTRA_ACCOUNT_KEY] = accountKey

View File

@ -19,8 +19,8 @@
package org.mariotaku.twidere.fragment.content package org.mariotaku.twidere.fragment.content
import android.accounts.AccountManager
import android.app.Dialog import android.app.Dialog
import android.content.Context
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
@ -30,15 +30,19 @@ import android.support.annotation.CheckResult
import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentManager
import android.support.v7.app.AlertDialog import android.support.v7.app.AlertDialog
import android.support.v7.widget.PopupMenu import android.support.v7.widget.PopupMenu
import android.text.Editable
import android.text.TextWatcher
import android.view.Gravity import android.view.Gravity
import android.view.View import android.view.View
import android.widget.* import android.widget.EditText
import android.widget.ImageButton
import android.widget.RelativeLayout
import android.widget.Toast
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.twitter.Validator import com.twitter.Validator
import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.task
import org.mariotaku.ktextension.* import org.mariotaku.ktextension.*
import org.mariotaku.library.objectcursor.ObjectCursor import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.activity.content.RetweetQuoteDialogActivity import org.mariotaku.twidere.activity.content.RetweetQuoteDialogActivity
import org.mariotaku.twidere.adapter.DummyItemAdapter import org.mariotaku.twidere.adapter.DummyItemAdapter
@ -46,18 +50,19 @@ 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.extension.model.newMicroBlogInstance
import org.mariotaku.twidere.extension.model.textLimit import org.mariotaku.twidere.extension.model.textLimit
import org.mariotaku.twidere.fragment.BaseDialogFragment import org.mariotaku.twidere.fragment.BaseDialogFragment
import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.draft.QuoteStatusActionExtras import org.mariotaku.twidere.model.draft.QuoteStatusActionExtras
import org.mariotaku.twidere.model.util.AccountUtils import org.mariotaku.twidere.model.util.ParcelableStatusUtils
import org.mariotaku.twidere.provider.TwidereDataStore.Drafts import org.mariotaku.twidere.provider.TwidereDataStore.Drafts
import org.mariotaku.twidere.service.LengthyOperationsService import org.mariotaku.twidere.service.LengthyOperationsService
import org.mariotaku.twidere.util.Analyzer import org.mariotaku.twidere.util.Analyzer
import org.mariotaku.twidere.util.EditTextEnterHandler import org.mariotaku.twidere.util.EditTextEnterHandler
import org.mariotaku.twidere.util.LinkCreator import org.mariotaku.twidere.util.LinkCreator
import org.mariotaku.twidere.util.Utils.isMyRetweet import org.mariotaku.twidere.util.Utils.isMyRetweet
import org.mariotaku.twidere.view.ColorLabelRelativeLayout import org.mariotaku.twidere.util.view.SimpleTextWatcher
import org.mariotaku.twidere.view.ComposeEditText import org.mariotaku.twidere.view.ComposeEditText
import org.mariotaku.twidere.view.StatusTextCountView import org.mariotaku.twidere.view.StatusTextCountView
import org.mariotaku.twidere.view.holder.StatusViewHolder import org.mariotaku.twidere.view.holder.StatusViewHolder
@ -66,46 +71,100 @@ import java.util.*
/** /**
* Asks user to retweet/quote a status. * Asks user to retweet/quote a status.
*/ */
class RetweetQuoteDialogFragment : BaseDialogFragment() { class RetweetQuoteDialogFragment : AbsStatusDialogFragment() {
override val Dialog.loadProgress: View get() = findViewById(R.id.loadProgress)
override val Dialog.itemContent: View get() = findViewById(R.id.itemContent)
private lateinit var popupMenu: PopupMenu private lateinit var popupMenu: PopupMenu
private val PopupMenu.quoteOriginalStatus get() = menu.isItemChecked(R.id.quote_original_status)
private val Dialog.loadProgress get() = findViewById(R.id.loadProgress)
private val Dialog.itemContent get() = findViewById(R.id.itemContent) as ColorLabelRelativeLayout
private val Dialog.textCountView get() = findViewById(R.id.commentTextCount) as StatusTextCountView private val Dialog.textCountView get() = findViewById(R.id.commentTextCount) as StatusTextCountView
private val Dialog.itemMenu get() = findViewById(R.id.itemMenu) as ImageButton
private val Dialog.actionButtons get() = findViewById(R.id.actionButtons) as LinearLayout
private val Dialog.commentContainer get() = findViewById(R.id.commentContainer) as RelativeLayout private val Dialog.commentContainer get() = findViewById(R.id.commentContainer) as RelativeLayout
private val Dialog.editComment get() = findViewById(R.id.editComment) as ComposeEditText private val Dialog.editComment get() = findViewById(R.id.editComment) as ComposeEditText
private val Dialog.commentMenu get() = findViewById(R.id.commentMenu) as ImageButton private val Dialog.commentMenu get() = findViewById(R.id.commentMenu) as ImageButton
private val PopupMenu.quoteOriginalStatus get() = menu.isItemChecked(R.id.quote_original_status)
private val status: ParcelableStatus
get() = arguments.getParcelable<ParcelableStatus>(EXTRA_STATUS)
private val accountKey: UserKey
get() = arguments.getParcelable(EXTRA_ACCOUNT_KEY) ?: status.account_key
private val text: String? private val text: String?
get() = arguments.getString(EXTRA_TEXT) get() = arguments.getString(EXTRA_TEXT)
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun AlertDialog.Builder.setupAlertDialog() {
val builder = AlertDialog.Builder(context) setTitle(R.string.title_retweet_quote_confirm)
val accountKey = this.accountKey setView(R.layout.dialog_status_quote_retweet)
val details = AccountUtils.getAccountDetails(AccountManager.get(context), accountKey, true)!! setPositiveButton(R.string.action_retweet, null)
val status = this.status.apply { setNegativeButton(android.R.string.cancel, null)
if (account_key != accountKey) { setNeutralButton(R.string.action_quote, null)
my_retweet_id = null }
}
account_key = details.key
account_color = details.color
}
builder.setView(R.layout.dialog_status_quote_retweet) override fun AlertDialog.onStatusLoaded(details: AccountDetails, status: ParcelableStatus,
builder.setTitle(R.string.title_retweet_quote_confirm) savedInstanceState: Bundle?) {
builder.setPositiveButton(R.string.action_retweet, null)
builder.setNegativeButton(android.R.string.cancel, null) val adapter = DummyItemAdapter(context, requestManager = Glide.with(this@RetweetQuoteDialogFragment))
builder.setNeutralButton(R.string.action_quote) { _, _ -> adapter.setShouldShowAccountsColor(true)
val holder = StatusViewHolder(adapter, itemContent)
holder.displayStatus(status = status, displayInReplyTo = false)
textCountView.maxLength = details.textLimit
val useQuote = useQuote(!status.user_is_protected, details)
commentContainer.visibility = if (useQuote) View.VISIBLE else View.GONE
editComment.accountKey = details.key
val enterHandler = EditTextEnterHandler.attach(editComment, object : EditTextEnterHandler.EnterListener {
override fun shouldCallListener(): Boolean {
return true
}
override fun onHitEnter(): Boolean {
if (retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)) {
dismiss()
return true
}
return false
}
}, preferences.getBoolean(KEY_QUICK_SEND))
enterHandler.addTextChangedListener(object : SimpleTextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
updateTextCount(getDialog(), s, status, details)
}
})
popupMenu = PopupMenu(context, commentMenu, Gravity.NO_GRAVITY,
R.attr.actionOverflowMenuStyle, 0).apply {
inflate(R.menu.menu_dialog_comment)
menu.setItemAvailability(R.id.quote_original_status, status.retweet_id != null || status.quoted_id != null)
setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener { item ->
if (item.isCheckable) {
item.isChecked = !item.isChecked
return@OnMenuItemClickListener true
}
false
})
}
commentMenu.setOnClickListener { popupMenu.show() }
commentMenu.setOnTouchListener(popupMenu.dragToOpenListener)
commentMenu.visibility = if (popupMenu.menu.hasVisibleItems()) View.VISIBLE else View.GONE
getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
var dismissDialog = false
if (editComment.length() > 0) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else if (isMyRetweet(status)) {
twitterWrapper.cancelRetweetAsync(details.key, status.id, status.my_retweet_id)
dismissDialog = true
} else if (useQuote(!status.user_is_protected, details)) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else {
Analyzer.logException(IllegalStateException(status.toString()))
}
if (dismissDialog) {
dismiss()
}
}
getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener {
val intent = Intent(INTENT_ACTION_QUOTE) val intent = Intent(INTENT_ACTION_QUOTE)
val menu = popupMenu.menu val menu = popupMenu.menu
val quoteOriginalStatus = menu.findItem(R.id.quote_original_status) val quoteOriginalStatus = menu.findItem(R.id.quote_original_status)
@ -114,96 +173,12 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
startActivity(intent) startActivity(intent)
} }
val dialog = builder.create() if (savedInstanceState == null) {
dialog.setOnShowListener { dialog -> editComment.setText(text)
dialog as AlertDialog
dialog.applyTheme()
val adapter = DummyItemAdapter(context, requestManager = Glide.with(this))
adapter.setShouldShowAccountsColor(true)
val holder = StatusViewHolder(adapter, dialog.itemContent)
holder.displayStatus(status = status, displayInReplyTo = false)
dialog.textCountView.maxLength = details.textLimit
dialog.loadProgress.visibility = View.GONE
dialog.itemMenu.visibility = View.GONE
dialog.actionButtons.visibility = View.GONE
dialog.itemContent.isFocusable = false
val useQuote = useQuote(!status.user_is_protected, details)
dialog.commentContainer.visibility = if (useQuote) View.VISIBLE else View.GONE
dialog.editComment.accountKey = details.key
val sendByEnter = preferences.getBoolean(KEY_QUICK_SEND)
val enterHandler = EditTextEnterHandler.attach(dialog.editComment, object : EditTextEnterHandler.EnterListener {
override fun shouldCallListener(): Boolean {
return true
}
override fun onHitEnter(): Boolean {
if (retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)) {
dismiss()
return true
}
return false
}
}, sendByEnter)
enterHandler.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
updateTextCount(getDialog(), s, status, details)
}
override fun afterTextChanged(s: Editable) {
}
})
popupMenu = PopupMenu(context, dialog.commentMenu, Gravity.NO_GRAVITY,
R.attr.actionOverflowMenuStyle, 0).apply {
inflate(R.menu.menu_dialog_comment)
menu.setItemAvailability(R.id.quote_original_status, status.retweet_id != null || status.quoted_id != null)
setOnMenuItemClickListener(PopupMenu.OnMenuItemClickListener { item ->
if (item.isCheckable) {
item.isChecked = !item.isChecked
return@OnMenuItemClickListener true
}
false
})
}
dialog.commentMenu.setOnClickListener { popupMenu.show() }
dialog.commentMenu.setOnTouchListener(popupMenu.dragToOpenListener)
dialog.commentMenu.visibility = if (popupMenu.menu.hasVisibleItems()) View.VISIBLE else View.GONE
dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
var dismissDialog = false
if (dialog.editComment.length() > 0) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else if (isMyRetweet(status)) {
twitterWrapper.cancelRetweetAsync(details.key, status.id, status.my_retweet_id)
dismissDialog = true
} else if (useQuote(!status.user_is_protected, details)) {
dismissDialog = retweetOrQuote(details, status, SHOW_PROTECTED_CONFIRM)
} else {
Analyzer.logException(IllegalStateException(status.toString()))
}
if (dismissDialog) {
dismiss()
}
}
if (savedInstanceState == null) {
dialog.editComment.setText(text)
}
dialog.editComment.setSelection(dialog.editComment.length())
updateTextCount(dialog, dialog.editComment.text, status, details)
} }
return dialog editComment.setSelection(editComment.length())
updateTextCount(dialog, editComment.text, status, details)
} }
override fun onCancel(dialog: DialogInterface) { override fun onCancel(dialog: DialogInterface) {
@ -311,7 +286,6 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
return preCondition || AccountType.FANFOU == account.type return preCondition || AccountType.FANFOU == account.type
} }
private fun Dialog.saveToDrafts() { private fun Dialog.saveToDrafts() {
val text = dialog.editComment.text.toString() val text = dialog.editComment.text.toString()
val draft = Draft() val draft = Draft()
@ -391,8 +365,9 @@ 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, accountKey: UserKey? = null, statusId: String, fun show(fm: FragmentManager, accountKey: UserKey, statusId: String,
status: ParcelableStatus?, text: String? = null): RetweetQuoteDialogFragment { status: ParcelableStatus? = null, text: String? = null):
RetweetQuoteDialogFragment {
val f = RetweetQuoteDialogFragment() val f = RetweetQuoteDialogFragment()
f.arguments = Bundle { f.arguments = Bundle {
this[EXTRA_ACCOUNT_KEY] = accountKey this[EXTRA_ACCOUNT_KEY] = accountKey
@ -403,5 +378,26 @@ class RetweetQuoteDialogFragment : BaseDialogFragment() {
f.show(fm, FRAGMENT_TAG) f.show(fm, FRAGMENT_TAG)
return f return f
} }
fun showStatus(context: Context, details: AccountDetails, statusId: String,
status: ParcelableStatus?): Promise<ParcelableStatus, Exception> {
if (status != null) {
status.apply {
if (account_key != details.key) {
my_retweet_id = null
}
account_key = details.key
account_color = details.color
}
return Promise.ofSuccess(status)
}
val microBlog = details.newMicroBlogInstance(context, MicroBlog::class.java)
val profileImageSize = context.getString(R.string.profile_image_size)
return task {
ParcelableStatusUtils.fromStatus(microBlog.showStatus(statusId), details.key,
details.type, profileImageSize = profileImageSize)
}
}
} }
} }

View File

@ -17,6 +17,7 @@ import org.mariotaku.twidere.R
import org.mariotaku.twidere.TwidereConstants.* import org.mariotaku.twidere.TwidereConstants.*
import org.mariotaku.twidere.activity.MediaViewerActivity import org.mariotaku.twidere.activity.MediaViewerActivity
import org.mariotaku.twidere.annotation.Referral import org.mariotaku.twidere.annotation.Referral
import org.mariotaku.twidere.constant.IntentConstants
import org.mariotaku.twidere.fragment.SensitiveContentWarningDialogFragment import org.mariotaku.twidere.fragment.SensitiveContentWarningDialogFragment
import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.util.ParcelableLocationUtils import org.mariotaku.twidere.model.util.ParcelableLocationUtils
@ -77,13 +78,15 @@ object IntentUtils {
} }
fun userProfile(accountKey: UserKey?, userKey: UserKey?, screenName: String?, fun userProfile(accountKey: UserKey?, userKey: UserKey?, screenName: String?,
@Referral referral: String? = null, profileUrl: String? = null): Intent { @Referral referral: String? = null, profileUrl: String? = null,
accountHost: String? = accountKey?.host ?: userKey?.host): Intent {
val uri = LinkCreator.getTwidereUserLink(accountKey, userKey, screenName) val uri = LinkCreator.getTwidereUserLink(accountKey, userKey, screenName)
val intent = Intent(Intent.ACTION_VIEW, uri) val intent = Intent(Intent.ACTION_VIEW, uri)
if (referral != null) { if (referral != null) {
intent.putExtra(EXTRA_REFERRAL, referral) intent.putExtra(EXTRA_REFERRAL, referral)
} }
intent.putExtra(EXTRA_PROFILE_URL, profileUrl) intent.putExtra(EXTRA_PROFILE_URL, profileUrl)
intent.putExtra(EXTRA_ACCOUNT_HOST, accountHost)
return intent return intent
} }

View File

@ -39,7 +39,7 @@
android:id="@+id/loadProgress" android:id="@+id/loadProgress"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="96dp"> android:minHeight="@dimen/element_size_mlarge">
<ProgressBar <ProgressBar
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -94,7 +94,7 @@
android:id="@+id/loadProgress" android:id="@+id/loadProgress"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:minHeight="96dp"> android:minHeight="@dimen/element_size_mlarge">
<ProgressBar <ProgressBar
android:layout_width="wrap_content" android:layout_width="wrap_content"