mirror of
https://github.com/TwidereProject/Twidere-Android
synced 2025-02-17 04:00:48 +01:00
improved gap load
This commit is contained in:
parent
66ff961f2d
commit
f6aa30a66a
@ -72,7 +72,7 @@ public class ParcelableStatus implements Parcelable, Comparable<ParcelableStatus
|
||||
}
|
||||
};
|
||||
@CursorField(value = Statuses._ID, excludeWrite = true, type = TwidereDataStore.TYPE_PRIMARY_KEY)
|
||||
long _id;
|
||||
public long _id;
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
@ParcelableThisPlease
|
||||
|
@ -498,6 +498,7 @@ public class AsyncTwitterWrapper extends TwitterWrapper {
|
||||
return asyncTaskManager.add(task, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static <T extends Response<?>> Exception getException(List<T> responses) {
|
||||
for (T response : responses) {
|
||||
if (response.hasException()) return response.getException();
|
||||
|
@ -237,7 +237,7 @@ class ParcelableActivitiesAdapter(
|
||||
}
|
||||
ITEM_VIEW_TYPE_GAP -> {
|
||||
val activity = getActivity(position)!!
|
||||
val loading = gapLoadingIds.find { it.accountKey == activity.account_key && it.id == activity.id } != null
|
||||
val loading = gapLoadingIds.any { it.accountKey == activity.account_key && it.id == activity.id }
|
||||
(holder as GapViewHolder).display(loading)
|
||||
}
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ abstract class ParcelableStatusesAdapter(
|
||||
(holder as IStatusViewHolder).displayStatus(status, isShowInReplyTo)
|
||||
}
|
||||
ITEM_VIEW_TYPE_GAP -> {
|
||||
val loading = gapLoadingIds.find { it.accountKey == status.account_key && it.id == status.id } != null
|
||||
val loading = gapLoadingIds.any { it.accountKey == status.account_key && it.id == status.id }
|
||||
(holder as GapViewHolder).display(loading)
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +274,7 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||
if (loader is IExtendedLoader) {
|
||||
loader.fromUser = false
|
||||
}
|
||||
onLoadingFinished()
|
||||
onContentLoaded(loader, data)
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<List<ParcelableActivity>>) {
|
||||
@ -434,7 +434,7 @@ abstract class AbsActivitiesFragment protected constructor() :
|
||||
protected abstract fun onCreateActivitiesLoader(context: Context, args: Bundle,
|
||||
fromUser: Boolean): Loader<List<ParcelableActivity>>
|
||||
|
||||
protected abstract fun onLoadingFinished()
|
||||
protected abstract fun onContentLoaded(loader: Loader<List<ParcelableActivity>>, data: List<ParcelableActivity>?)
|
||||
|
||||
protected fun saveReadPosition(position: Int) {
|
||||
if (host == null) return
|
||||
|
@ -28,6 +28,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.v4.content.Loader
|
||||
import android.widget.Toast
|
||||
import com.squareup.otto.Subscribe
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
|
||||
@ -44,6 +45,7 @@ import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.message.*
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
||||
import org.mariotaku.twidere.task.twitter.GetStatusesTask
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.DataStoreUtils.getTableNameByUri
|
||||
import org.mariotaku.twidere.util.ErrorInfoStore
|
||||
@ -55,32 +57,26 @@ import org.mariotaku.twidere.util.Utils
|
||||
*/
|
||||
abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
|
||||
override fun onLoadingFinished() {
|
||||
val accountKeys = accountKeys
|
||||
if (adapter.itemCount > 0) {
|
||||
showContent()
|
||||
} else if (accountKeys.isNotEmpty()) {
|
||||
val errorInfo = ErrorInfoStore.getErrorInfo(context,
|
||||
errorInfoStore[errorInfoKey, accountKeys[0]])
|
||||
if (errorInfo != null) {
|
||||
showEmpty(errorInfo.icon, errorInfo.message)
|
||||
} else {
|
||||
showEmpty(R.drawable.ic_info_refresh, getString(R.string.swipe_down_to_refresh))
|
||||
}
|
||||
} else {
|
||||
showError(R.drawable.ic_info_accounts, getString(R.string.message_toast_no_account_selected))
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract val errorInfoKey: String
|
||||
|
||||
private var contentObserver: ContentObserver? = null
|
||||
|
||||
private val accountListener: OnAccountsUpdateListener = OnAccountsUpdateListener { accounts ->
|
||||
reloadActivities()
|
||||
}
|
||||
|
||||
override val accountKeys: Array<UserKey>
|
||||
get() = Utils.getAccountKeys(context, arguments) ?: DataStoreUtils.getActivatedAccountKeys(context)
|
||||
|
||||
protected abstract val errorInfoKey: String
|
||||
|
||||
private val sortOrder: String
|
||||
get() = Activities.DEFAULT_SORT_ORDER
|
||||
|
||||
abstract val contentUri: Uri
|
||||
|
||||
override fun onContentLoaded(loader: Loader<List<ParcelableActivity>>, data: List<ParcelableActivity>?) {
|
||||
showContentOrError()
|
||||
}
|
||||
|
||||
override fun onCreateActivitiesLoader(context: Context,
|
||||
args: Bundle,
|
||||
fromUser: Boolean): Loader<List<ParcelableActivity>> {
|
||||
@ -113,9 +109,6 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
return CursorActivitiesBusCallback()
|
||||
}
|
||||
|
||||
override val accountKeys: Array<UserKey>
|
||||
get() = Utils.getAccountKeys(context, arguments) ?: DataStoreUtils.getActivatedAccountKeys(context)
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
if (contentObserver == null) {
|
||||
@ -140,17 +133,6 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
protected fun reloadActivities() {
|
||||
if (activity == null || isDetached) return
|
||||
val args = Bundle()
|
||||
val fragmentArgs = arguments
|
||||
if (fragmentArgs != null) {
|
||||
args.putAll(fragmentArgs)
|
||||
args.putBoolean(EXTRA_FROM_USER, true)
|
||||
}
|
||||
loaderManager.restartLoader(0, args, this)
|
||||
}
|
||||
|
||||
override fun hasMoreData(data: List<ParcelableActivity>?): Boolean {
|
||||
return data?.size != 0
|
||||
}
|
||||
@ -249,8 +231,34 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
|
||||
protected abstract fun updateRefreshState()
|
||||
|
||||
private val sortOrder: String
|
||||
get() = Activities.DEFAULT_SORT_ORDER
|
||||
|
||||
protected fun reloadActivities() {
|
||||
if (activity == null || isDetached) return
|
||||
val args = Bundle()
|
||||
val fragmentArgs = arguments
|
||||
if (fragmentArgs != null) {
|
||||
args.putAll(fragmentArgs)
|
||||
args.putBoolean(EXTRA_FROM_USER, true)
|
||||
}
|
||||
loaderManager.restartLoader(0, args, this)
|
||||
}
|
||||
|
||||
private fun showContentOrError() {
|
||||
val accountKeys = accountKeys
|
||||
if (adapter.itemCount > 0) {
|
||||
showContent()
|
||||
} else if (accountKeys.isNotEmpty()) {
|
||||
val errorInfo = ErrorInfoStore.getErrorInfo(context,
|
||||
errorInfoStore[errorInfoKey, accountKeys[0]])
|
||||
if (errorInfo != null) {
|
||||
showEmpty(errorInfo.icon, errorInfo.message)
|
||||
} else {
|
||||
showEmpty(R.drawable.ic_info_refresh, getString(R.string.swipe_down_to_refresh))
|
||||
}
|
||||
} else {
|
||||
showError(R.drawable.ic_info_accounts, getString(R.string.message_toast_no_account_selected))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun updateFavoritedStatus(status: ParcelableStatus) {
|
||||
@ -296,7 +304,11 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
|
||||
if (!event.running) {
|
||||
setLoadMoreIndicatorPosition(ILoadMoreSupportAdapter.NONE)
|
||||
refreshEnabled = true
|
||||
onLoadingFinished()
|
||||
showContentOrError()
|
||||
|
||||
if (event.exception is GetStatusesTask.GetTimelineException && userVisibleHint) {
|
||||
Toast.makeText(context, event.exception.getToastMessage(context), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.support.v4.content.Loader
|
||||
import android.widget.Toast
|
||||
import com.squareup.otto.Subscribe
|
||||
import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
|
||||
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
|
||||
@ -44,6 +45,7 @@ import org.mariotaku.twidere.model.*
|
||||
import org.mariotaku.twidere.model.message.*
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Filters
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.task.twitter.GetStatusesTask
|
||||
import org.mariotaku.twidere.util.DataStoreUtils
|
||||
import org.mariotaku.twidere.util.ErrorInfoStore
|
||||
import org.mariotaku.twidere.util.Utils
|
||||
@ -263,6 +265,10 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
|
||||
setLoadMoreIndicatorPosition(ILoadMoreSupportAdapter.NONE)
|
||||
refreshEnabled = true
|
||||
showContentOrError()
|
||||
|
||||
if (event.exception is GetStatusesTask.GetTimelineException && userVisibleHint) {
|
||||
Toast.makeText(context, event.exception.getToastMessage(context), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.model.util.ParcelableActivityUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||
import org.mariotaku.twidere.util.*
|
||||
import org.mariotaku.twidere.util.TwitterWrapper.TwitterListResponse
|
||||
import org.mariotaku.twidere.util.content.ContentResolverUtils
|
||||
import org.mariotaku.twidere.util.dagger.GeneralComponentHelper
|
||||
import java.util.*
|
||||
@ -37,7 +38,7 @@ import javax.inject.Inject
|
||||
*/
|
||||
abstract class GetActivitiesTask(
|
||||
protected val context: Context
|
||||
) : AbstractTask<RefreshTaskParam, Unit, (Boolean) -> Unit>() {
|
||||
) : AbstractTask<RefreshTaskParam, List<TwitterListResponse<Activity>>, (Boolean) -> Unit>() {
|
||||
private var initialized: Boolean = false
|
||||
@Inject
|
||||
lateinit var preferences: KPreferences
|
||||
@ -61,13 +62,14 @@ abstract class GetActivitiesTask(
|
||||
initialized = true
|
||||
}
|
||||
|
||||
override fun doLongOperation(param: RefreshTaskParam) {
|
||||
if (!initialized || param.shouldAbort) return
|
||||
override fun doLongOperation(param: RefreshTaskParam): List<TwitterListResponse<Activity>> {
|
||||
if (!initialized || param.shouldAbort) return emptyList()
|
||||
val accountIds = param.accountKeys
|
||||
val maxIds = param.maxIds
|
||||
val maxSortIds = param.maxSortIds
|
||||
val sinceIds = param.sinceIds
|
||||
val cr = context.contentResolver
|
||||
val result = ArrayList<TwitterListResponse<Activity>>()
|
||||
val loadItemLimit = preferences[loadItemLimitKey]
|
||||
var saveReadPosition = false
|
||||
for (i in accountIds.indices) {
|
||||
@ -102,12 +104,15 @@ abstract class GetActivitiesTask(
|
||||
// We should delete old activities has intersection with new items
|
||||
try {
|
||||
val activities = getActivities(microBlog, credentials, paging)
|
||||
storeActivities(cr, loadItemLimit, credentials, noItemsBefore, activities, sinceId,
|
||||
val storeResult = storeActivities(cr, loadItemLimit, credentials, noItemsBefore, activities, sinceId,
|
||||
maxId, false)
|
||||
if (saveReadPosition) {
|
||||
saveReadPosition(accountKey, credentials, microBlog)
|
||||
}
|
||||
errorInfoStore.remove(errorInfoKey, accountKey)
|
||||
if (storeResult != 0) {
|
||||
throw GetStatusesTask.GetTimelineException(storeResult)
|
||||
}
|
||||
} catch (e: MicroBlogException) {
|
||||
DebugLog.w(LOGTAG, tr = e)
|
||||
if (e.errorCode == 220) {
|
||||
@ -115,21 +120,24 @@ abstract class GetActivitiesTask(
|
||||
} else if (e.isCausedByNetworkIssue) {
|
||||
errorInfoStore[errorInfoKey, accountKey] = ErrorInfoStore.CODE_NETWORK_ERROR
|
||||
}
|
||||
} catch (e: GetStatusesTask.GetTimelineException) {
|
||||
result.add(TwitterListResponse(accountKey, e))
|
||||
}
|
||||
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
override fun afterExecute(handler: ((Boolean) -> Unit)?, result: Unit) {
|
||||
override fun afterExecute(handler: ((Boolean) -> Unit)?, result: List<TwitterListResponse<Activity>>) {
|
||||
if (!initialized) return
|
||||
context.contentResolver.notifyChange(contentUri, null)
|
||||
bus.post(GetActivitiesTaskEvent(contentUri, false, null))
|
||||
val exception = AsyncTwitterWrapper.getException(result)
|
||||
bus.post(GetActivitiesTaskEvent(contentUri, false, exception))
|
||||
handler?.invoke(true)
|
||||
}
|
||||
|
||||
private fun storeActivities(cr: ContentResolver, loadItemLimit: Int, details: AccountDetails,
|
||||
noItemsBefore: Boolean, activities: ResponseList<Activity>,
|
||||
sinceId: String?, maxId: String?, notify: Boolean) {
|
||||
sinceId: String?, maxId: String?, notify: Boolean): Int {
|
||||
val deleteBound = LongArray(2) { -1 }
|
||||
val valuesList = ArrayList<ContentValues>()
|
||||
var minIdx = -1
|
||||
@ -185,17 +193,25 @@ abstract class GetActivitiesTask(
|
||||
valuesList[valuesList.size - 1].put(Activities.IS_GAP, true)
|
||||
}
|
||||
}
|
||||
// Insert previously fetched items.
|
||||
ContentResolverUtils.bulkInsert(cr, writeUri, valuesList)
|
||||
|
||||
// Remove gap flag
|
||||
if (maxId != null && sinceId == null) {
|
||||
val noGapValues = ContentValues()
|
||||
noGapValues.put(Activities.IS_GAP, false)
|
||||
val noGapWhere = Expression.and(Expression.equalsArgs(Activities.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Activities.MIN_REQUEST_POSITION),
|
||||
Expression.equalsArgs(Activities.MAX_REQUEST_POSITION)).sql
|
||||
val noGapWhereArgs = arrayOf(details.key.toString(), maxId, maxId)
|
||||
cr.update(writeUri, noGapValues, noGapWhere, noGapWhereArgs)
|
||||
if (activities.isNotEmpty()) {
|
||||
// Only remove when actual result returned, otherwise it seems that gap is too old to load
|
||||
val noGapValues = ContentValues()
|
||||
noGapValues.put(Activities.IS_GAP, false)
|
||||
val noGapWhere = Expression.and(Expression.equalsArgs(Activities.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Activities.MIN_REQUEST_POSITION),
|
||||
Expression.equalsArgs(Activities.MAX_REQUEST_POSITION)).sql
|
||||
val noGapWhereArgs = arrayOf(details.key.toString(), maxId, maxId)
|
||||
cr.update(writeUri, noGapValues, noGapWhere, noGapWhereArgs)
|
||||
} else {
|
||||
return GetStatusesTask.ERROR_LOAD_GAP
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
@UiThread
|
||||
|
@ -19,6 +19,7 @@ import org.mariotaku.microblog.library.twitter.model.ResponseList
|
||||
import org.mariotaku.microblog.library.twitter.model.Status
|
||||
import org.mariotaku.sqliteqb.library.Columns
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.LOGTAG
|
||||
import org.mariotaku.twidere.TwidereConstants.QUERY_PARAM_NOTIFY
|
||||
import org.mariotaku.twidere.constant.loadItemLimitKey
|
||||
@ -123,13 +124,18 @@ abstract class GetStatusesTask(
|
||||
sinceId = null
|
||||
}
|
||||
val statuses = getStatuses(microBlog, paging)
|
||||
storeStatus(accountKey, details, statuses, sinceId, maxId, sinceSortId,
|
||||
val storeResult = storeStatus(accountKey, details, statuses, sinceId, maxId, sinceSortId,
|
||||
maxSortId, loadItemLimit, false)
|
||||
// TODO cache related data and preload
|
||||
val cacheTask = CacheUsersStatusesTask(context)
|
||||
cacheTask.params = TwitterWrapper.StatusListResponse(accountKey, statuses)
|
||||
val response = TwitterWrapper.StatusListResponse(accountKey, statuses)
|
||||
cacheTask.params = response
|
||||
TaskStarter.execute(cacheTask)
|
||||
errorInfoStore.remove(errorInfoKey, accountKey.id)
|
||||
result.add(response)
|
||||
if (storeResult != 0) {
|
||||
throw GetTimelineException(storeResult)
|
||||
}
|
||||
} catch (e: MicroBlogException) {
|
||||
DebugLog.w(LOGTAG, tr = e)
|
||||
if (e.isCausedByNetworkIssue) {
|
||||
@ -138,6 +144,8 @@ abstract class GetStatusesTask(
|
||||
// Unauthorized
|
||||
}
|
||||
result.add(TwitterWrapper.StatusListResponse(accountKey, e))
|
||||
} catch (e: GetTimelineException) {
|
||||
result.add(TwitterWrapper.StatusListResponse(accountKey, e))
|
||||
}
|
||||
}
|
||||
return result
|
||||
@ -146,7 +154,8 @@ abstract class GetStatusesTask(
|
||||
override fun afterExecute(handler: ((Boolean) -> Unit)?, result: List<TwitterWrapper.StatusListResponse>) {
|
||||
if (!initialized) return
|
||||
context.contentResolver.notifyChange(contentUri, null)
|
||||
bus.post(GetStatusesTaskEvent(contentUri, false, AsyncTwitterWrapper.getException(result)))
|
||||
val exception = AsyncTwitterWrapper.getException(result)
|
||||
bus.post(GetStatusesTaskEvent(contentUri, false, exception))
|
||||
handler?.invoke(true)
|
||||
}
|
||||
|
||||
@ -159,7 +168,7 @@ abstract class GetStatusesTask(
|
||||
statuses: List<Status>,
|
||||
sinceId: String?, maxId: String?,
|
||||
sinceSortId: Long, maxSortId: Long,
|
||||
loadItemLimit: Int, notify: Boolean) {
|
||||
loadItemLimit: Int, notify: Boolean): Int {
|
||||
val uri = contentUri
|
||||
val writeUri = UriUtils.appendQueryParameters(uri, QUERY_PARAM_NOTIFY, notify)
|
||||
val resolver = context.contentResolver
|
||||
@ -227,17 +236,34 @@ abstract class GetStatusesTask(
|
||||
|
||||
// Remove gap flag
|
||||
if (maxId != null && sinceId == null) {
|
||||
val noGapValues = ContentValues()
|
||||
noGapValues.put(Statuses.IS_GAP, false)
|
||||
val noGapWhere = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Statuses.STATUS_ID)).sql
|
||||
val noGapWhereArgs = arrayOf(accountKey.toString(), maxId)
|
||||
resolver.update(writeUri, noGapValues, noGapWhere, noGapWhereArgs)
|
||||
if (statuses.isNotEmpty()) {
|
||||
// Only remove when actual result returned, otherwise it seems that gap is too old to load
|
||||
val noGapValues = ContentValues()
|
||||
noGapValues.put(Statuses.IS_GAP, false)
|
||||
val noGapWhere = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
|
||||
Expression.equalsArgs(Statuses.STATUS_ID)).sql
|
||||
val noGapWhereArgs = arrayOf(accountKey.toString(), maxId)
|
||||
resolver.update(writeUri, noGapValues, noGapWhere, noGapWhereArgs)
|
||||
} else {
|
||||
return ERROR_LOAD_GAP
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
class GetTimelineException(val code: Int) : Exception() {
|
||||
fun getToastMessage(context: Context): String {
|
||||
when (code) {
|
||||
ERROR_LOAD_GAP -> return context.getString(R.string.message_toast_unable_to_load_more_statuses)
|
||||
}
|
||||
return context.getString(R.string.error_unknown_error)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val ERROR_LOAD_GAP = 1
|
||||
|
||||
fun getPositionKey(timestamp: Long, sortId: Long, lastSortId: Long, sortDiff: Long,
|
||||
position: Int, count: Int): Long {
|
||||
if (sortDiff == 0L) return timestamp
|
||||
|
@ -22,6 +22,7 @@ package org.mariotaku.twidere.util
|
||||
import android.accounts.AccountManager
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.support.annotation.DrawableRes
|
||||
@ -39,6 +40,7 @@ import android.view.MenuItem
|
||||
import org.mariotaku.kpreferences.get
|
||||
import org.mariotaku.ktextension.setItemChecked
|
||||
import org.mariotaku.ktextension.setMenuItemIcon
|
||||
import org.mariotaku.sqliteqb.library.Expression
|
||||
import org.mariotaku.twidere.Constants
|
||||
import org.mariotaku.twidere.R
|
||||
import org.mariotaku.twidere.TwidereConstants.*
|
||||
@ -57,6 +59,7 @@ import org.mariotaku.twidere.menu.SupportStatusShareProvider
|
||||
import org.mariotaku.twidere.model.AccountDetails
|
||||
import org.mariotaku.twidere.model.ParcelableStatus
|
||||
import org.mariotaku.twidere.model.util.AccountUtils
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||
import org.mariotaku.twidere.util.menu.TwidereMenuInfo
|
||||
|
||||
/**
|
||||
@ -322,6 +325,14 @@ object MenuUtils {
|
||||
ClipboardUtils.setText(context, uri.toString())
|
||||
Utils.showOkMessage(context, R.string.message_toast_link_copied_to_clipboard, false)
|
||||
}
|
||||
R.id.make_gap -> {
|
||||
val resolver = context.contentResolver
|
||||
val values = ContentValues()
|
||||
values.put(Statuses.IS_GAP, 1)
|
||||
val where = Expression.equalsArgs(Statuses._ID).sql
|
||||
val whereArgs = arrayOf(status._id.toString())
|
||||
resolver.update(Statuses.CONTENT_URI, values, where, whereArgs)
|
||||
}
|
||||
else -> {
|
||||
if (item.intent != null) {
|
||||
try {
|
||||
|
@ -22,11 +22,8 @@ package org.mariotaku.twidere.view.holder
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.View
|
||||
import android.view.View.OnClickListener
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import kotlinx.android.synthetic.main.card_item_gap.view.*
|
||||
import org.mariotaku.twidere.R
|
||||
|
||||
import org.mariotaku.twidere.adapter.iface.IGapSupportedAdapter
|
||||
|
||||
/**
|
||||
@ -37,13 +34,11 @@ class GapViewHolder(
|
||||
itemView: View
|
||||
) : RecyclerView.ViewHolder(itemView), OnClickListener {
|
||||
|
||||
private val gapText: TextView
|
||||
private val gapProgress: ProgressBar
|
||||
private val gapText = itemView.gapText
|
||||
private val gapProgress = itemView.gapProgress
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
gapText = itemView.gapText
|
||||
gapProgress = itemView.gapProgress
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
@ -52,8 +47,14 @@ class GapViewHolder(
|
||||
}
|
||||
|
||||
fun display(showProgress: Boolean) {
|
||||
gapText.visibility = if (showProgress) View.GONE else View.VISIBLE
|
||||
gapProgress.visibility = if (showProgress) View.VISIBLE else View.GONE
|
||||
if (showProgress) {
|
||||
gapText.visibility = View.INVISIBLE
|
||||
gapProgress.visibility = View.VISIBLE
|
||||
gapProgress.spin()
|
||||
} else {
|
||||
gapText.visibility = View.VISIBLE
|
||||
gapProgress.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -21,6 +21,7 @@
|
||||
<FrameLayout
|
||||
android:id="@+id/gapIndicator"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/element_size_normal"
|
||||
android:focusable="true">
|
||||
@ -37,11 +38,15 @@
|
||||
android:textColor="?android:textColorPrimary"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<ProgressBar
|
||||
<com.pnikosis.materialishprogress.ProgressWheel
|
||||
android:id="@+id/gapProgress"
|
||||
style="?android:progressBarStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:visibility="gone"/>
|
||||
android:padding="@dimen/element_spacing_small"
|
||||
android:visibility="invisible"
|
||||
app:matProg_barColor="?colorAccent"
|
||||
app:matProg_barWidth="3dp"
|
||||
app:matProg_progressIndeterminate="true"/>
|
||||
</FrameLayout>
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<item
|
||||
android:id="@id/share"
|
||||
@ -34,5 +35,12 @@
|
||||
android:icon="@drawable/ic_action_delete"
|
||||
android:title="@string/action_delete"
|
||||
android:visible="false"/>
|
||||
<item
|
||||
android:id="@+id/make_gap"
|
||||
android:enabled="@bool/debug"
|
||||
android:title="Make gap"
|
||||
android:visible="@bool/debug"
|
||||
tools:ignore="HardcodedText"/>
|
||||
|
||||
|
||||
</menu>
|
@ -727,6 +727,7 @@
|
||||
<string name="message_toast_status_saved_to_draft">Tweet saved to draft</string>
|
||||
<string name="message_toast_status_unfavorited">Tweet unfavorited</string>
|
||||
<string name="message_toast_status_updated">Tweet sent</string>
|
||||
<string name="message_toast_unable_to_load_more_statuses">Unable to load more tweets</string>
|
||||
<string name="message_toast_user_filters_removed">Removed from filters</string>
|
||||
<string name="message_toast_users_filters_added">Added to filters</string>
|
||||
<string name="message_toast_wrong_api_key">Incorrect API settings</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user