improved clear notifications

This commit is contained in:
Mariotaku Lee 2017-04-23 22:00:54 +08:00
parent 63b56269ff
commit ae6df32777
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
5 changed files with 188 additions and 152 deletions

View File

@ -922,8 +922,8 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
}.fold(0L, Math::max)
val count = DataStoreUtils.getInteractionsCount(context, spec.args,
accountKeys, position, Activities.TIMESTAMP)
publishProgress(TabBadge(i, count))
result.put(i, count)
publishProgress(TabBadge(i, count))
}
CustomTabType.DIRECT_MESSAGES -> {
val accountKeys = Utils.getAccountKeys(context, spec.args) ?: activatedKeys
@ -935,8 +935,8 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
accountKeys, extraHaving = unreadHaving)?.useCursor { cur ->
return@useCursor cur.count
} ?: -1
publishProgress(TabBadge(i, count))
result.put(i, count)
publishProgress(TabBadge(i, count))
}
else -> {
publishProgress(TabBadge(i, -1))

View File

@ -28,8 +28,10 @@ import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.support.v4.content.Loader
import android.support.v7.widget.RecyclerView
import android.widget.Toast
import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.fragment_content_recyclerview.*
import org.mariotaku.ktextension.addOnAccountsUpdatedListenerSafe
import org.mariotaku.ktextension.contains
import org.mariotaku.ktextension.removeOnAccountsUpdatedListenerSafe
@ -59,24 +61,65 @@ import org.mariotaku.twidere.util.Utils
*/
abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
override val accountKeys: Array<UserKey>
get() = Utils.getAccountKeys(context, arguments) ?: DataStoreUtils.getActivatedAccountKeys(context)
abstract val contentUri: Uri
protected abstract val errorInfoKey: String
protected abstract val notificationType: Int
protected abstract val isFilterEnabled: Boolean
private var contentObserver: ContentObserver? = null
private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
clearNotifications()
}
}
}
private val accountListener: OnAccountsUpdateListener = OnAccountsUpdateListener {
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 onStart() {
super.onStart()
if (contentObserver == null) {
contentObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
reloadActivities()
}
}
context.contentResolver.registerContentObserver(Filters.CONTENT_URI, true, contentObserver)
}
AccountManager.get(context).addOnAccountsUpdatedListenerSafe(accountListener, updateImmediately = false)
recyclerView.addOnScrollListener(onScrollListener)
updateRefreshState()
reloadActivities()
}
override fun onContentLoaded(loader: Loader<List<ParcelableActivity>>, data: List<ParcelableActivity>?) {
showContentOrError()
override fun onStop() {
recyclerView.removeOnScrollListener(onScrollListener)
if (contentObserver != null) {
context.contentResolver.unregisterContentObserver(contentObserver)
contentObserver = null
}
AccountManager.get(context).removeOnAccountsUpdatedListenerSafe(accountListener)
super.onStop()
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser) {
clearNotifications()
}
}
override fun onCreateActivitiesLoader(context: Context, args: Bundle, fromUser: Boolean): Loader<List<ParcelableActivity>> {
@ -104,34 +147,14 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
sortOrder, fromUser)
}
override fun onContentLoaded(loader: Loader<List<ParcelableActivity>>, data: List<ParcelableActivity>?) {
showContentOrError()
}
override fun createMessageBusCallback(): Any {
return CursorActivitiesBusCallback()
}
override fun onStart() {
super.onStart()
if (contentObserver == null) {
contentObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
reloadActivities()
}
}
context.contentResolver.registerContentObserver(Filters.CONTENT_URI, true, contentObserver)
}
AccountManager.get(context).addOnAccountsUpdatedListenerSafe(accountListener, updateImmediately = false)
updateRefreshState()
reloadActivities()
}
override fun onStop() {
if (contentObserver != null) {
context.contentResolver.unregisterContentObserver(contentObserver)
contentObserver = null
}
AccountManager.get(context).removeOnAccountsUpdatedListenerSafe(accountListener)
super.onStop()
}
override fun hasMoreData(data: List<ParcelableActivity>?): Boolean {
return data?.size != 0
}
@ -167,7 +190,6 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
})
}
override fun triggerRefresh(): Boolean {
super.triggerRefresh()
val contentUri = this.contentUri
@ -198,28 +220,12 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
return DataStoreUtils.buildActivityFilterWhereClause(table, null)
}
protected abstract val notificationType: Int
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
val context = context
if (context != null && isVisibleToUser) {
val accountKeys = accountKeys
for (accountKey in accountKeys) {
twitterWrapper.clearNotificationAsync(notificationType, accountKey)
}
}
}
protected abstract val isFilterEnabled: Boolean
protected open fun processWhere(where: Expression, whereArgs: Array<String>): ParameterizedExpression {
return ParameterizedExpression(where, whereArgs)
}
protected abstract fun updateRefreshState()
protected fun reloadActivities() {
if (activity == null || isDetached) return
val args = Bundle()
@ -231,30 +237,6 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
loaderManager.restartLoader(loaderId, 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) {
activity ?: return
replaceStatusStates(status)
}
fun replaceStatusStates(result: ParcelableStatus?) {
if (result == null) return
val lm = layoutManager
@ -283,6 +265,36 @@ abstract class CursorActivitiesFragment : AbsActivitiesFragment() {
adapter.notifyItemRangeChanged(rangeStart, rangeEnd)
}
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) {
activity ?: return
replaceStatusStates(status)
}
private fun clearNotifications() {
if (context != null && userVisibleHint) {
for (accountKey in accountKeys) {
twitterWrapper.clearNotificationAsync(notificationType, accountKey)
}
}
}
protected inner class CursorActivitiesBusCallback {
@Subscribe

View File

@ -27,6 +27,7 @@ import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.support.v4.content.Loader
import android.support.v7.widget.RecyclerView
import android.widget.Toast
import com.bumptech.glide.Glide
import com.squareup.otto.Subscribe
@ -62,23 +63,63 @@ import org.mariotaku.twidere.util.buildStatusFilterWhereClause
*/
abstract class CursorStatusesFragment : AbsStatusesFragment() {
private var contentObserver: ContentObserver? = null
private val accountListener: OnAccountsUpdateListener = OnAccountsUpdateListener {
reloadStatuses()
}
abstract val errorInfoKey: String
abstract val isFilterEnabled: Boolean
abstract val notificationType: Int
abstract val contentUri: Uri
override var refreshing: Boolean
get() = swipeLayout.isRefreshing
set(value) {
super.refreshing = value
}
override val useSortIdAsReadPosition: Boolean
get() = false
override val accountKeys: Array<UserKey>
get() = Utils.getAccountKeys(context, arguments) ?: DataStoreUtils.getActivatedAccountKeys(context)
abstract val errorInfoKey: String
abstract val isFilterEnabled: Boolean
abstract val notificationType: Int
abstract val contentUri: Uri
private var contentObserver: ContentObserver? = null
private val accountListener: OnAccountsUpdateListener = OnAccountsUpdateListener {
reloadStatuses()
}
private val onScrollListener = object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView?, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
clearNotifications()
}
}
}
override fun onStart() {
super.onStart()
if (contentObserver == null) {
contentObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
reloadStatuses()
}
}
context.contentResolver.registerContentObserver(Filters.CONTENT_URI, true, contentObserver)
}
AccountManager.get(context).addOnAccountsUpdatedListenerSafe(accountListener, updateImmediately = false)
recyclerView.addOnScrollListener(onScrollListener)
updateRefreshState()
reloadStatuses()
}
override fun onStop() {
recyclerView.removeOnScrollListener(onScrollListener)
if (contentObserver != null) {
context.contentResolver.unregisterContentObserver(contentObserver)
contentObserver = null
}
AccountManager.get(context).removeOnAccountsUpdatedListenerSafe(accountListener)
super.onStop()
}
override fun onStatusesLoaded(loader: Loader<List<ParcelableStatus>?>, data: List<ParcelableStatus>?) {
showContentOrError()
}
@ -110,61 +151,6 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
return CursorStatusesBusCallback()
}
private fun showContentOrError() {
val accountKeys = this.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))
}
}
override val accountKeys: Array<UserKey>
get() = Utils.getAccountKeys(context, arguments) ?: DataStoreUtils.getActivatedAccountKeys(context)
override fun onStart() {
super.onStart()
if (contentObserver == null) {
contentObserver = object : ContentObserver(Handler()) {
override fun onChange(selfChange: Boolean) {
reloadStatuses()
}
}
context.contentResolver.registerContentObserver(Filters.CONTENT_URI, true, contentObserver)
}
AccountManager.get(context).addOnAccountsUpdatedListenerSafe(accountListener, updateImmediately = false)
updateRefreshState()
reloadStatuses()
}
override fun onStop() {
if (contentObserver != null) {
context.contentResolver.unregisterContentObserver(contentObserver)
contentObserver = null
}
AccountManager.get(context).removeOnAccountsUpdatedListenerSafe(accountListener)
super.onStop()
}
protected fun reloadStatuses() {
if (context == null || isDetached) return
val args = Bundle()
val fragmentArgs = arguments
if (fragmentArgs != null) {
args.putAll(fragmentArgs)
args.putBoolean(EXTRA_FROM_USER, true)
}
loaderManager.restartLoader(loaderId, args, this)
}
override fun hasMoreData(data: List<ParcelableStatus>?): Boolean {
return data?.size != 0
}
@ -221,27 +207,60 @@ abstract class CursorStatusesFragment : AbsStatusesFragment() {
return true
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
if (isVisibleToUser) {
clearNotifications()
}
}
protected fun getFiltersWhere(table: String): Expression? {
if (!isFilterEnabled) return null
return buildStatusFilterWhereClause(preferences, table, null)
}
override fun setUserVisibleHint(isVisibleToUser: Boolean) {
super.setUserVisibleHint(isVisibleToUser)
val context = context
if (context != null && isVisibleToUser) {
for (accountKey in accountKeys) {
twitterWrapper.clearNotificationAsync(notificationType, accountKey)
}
}
}
protected open fun processWhere(where: Expression, whereArgs: Array<String>): ParameterizedExpression {
return ParameterizedExpression(where, whereArgs)
}
protected abstract fun updateRefreshState()
protected fun reloadStatuses() {
if (context == null || isDetached) return
val args = Bundle()
val fragmentArgs = arguments
if (fragmentArgs != null) {
args.putAll(fragmentArgs)
args.putBoolean(EXTRA_FROM_USER, true)
}
loaderManager.restartLoader(loaderId, args, this)
}
private fun showContentOrError() {
val accountKeys = this.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 clearNotifications() {
if (context != null && userVisibleHint) {
for (accountKey in accountKeys) {
twitterWrapper.clearNotificationAsync(notificationType, accountKey)
}
}
}
protected inner class CursorStatusesBusCallback {
@Subscribe

View File

@ -81,7 +81,9 @@ class ContentNotificationManager(
val accountKey = pref.accountKey
val resources = context.resources
val selection = Expression.and(Expression.equalsArgs(Statuses.ACCOUNT_KEY),
Expression.greaterThan(Statuses.POSITION_KEY, minPositionKey))
Expression.greaterThan(Statuses.POSITION_KEY, minPositionKey),
Expression.notEquals(Statuses.IS_GAP, 1)
)
val selectionArgs = arrayOf(accountKey.toString())
val filteredSelection = buildStatusFilterWhereClause(preferences, Statuses.TABLE_NAME,
selection)
@ -164,7 +166,8 @@ class ContentNotificationManager(
val accountKey = pref.accountKey
val where = Expression.and(
Expression.equalsArgs(Activities.ACCOUNT_KEY),
Expression.greaterThan(Activities.POSITION_KEY, position)
Expression.greaterThan(Activities.POSITION_KEY, position),
Expression.notEquals(Activities.IS_GAP, 1)
).sql
val whereArgs = arrayOf(accountKey.toString())
@SuppressLint("Recycle")

View File

@ -31,6 +31,7 @@
<item>de</item>
<item>el</item>
<item>en_GB</item>
<item>en_US</item>
<item>es</item>
<item>fa</item>
<item>fi</item>
@ -77,7 +78,8 @@
<item>Danish</item>
<item>German</item>
<item>Greek</item>
<item>English (UK)</item>
<item>English (GB)</item>
<item>English (United States)</item>
<item>Spanish</item>
<item>Persian</item>
<item>Finnish</item>