diff --git a/twidere/src/main/kotlin/android/arch/paging/PagedListAdapterHelperExtensions.kt b/twidere/src/main/kotlin/android/arch/paging/PagedListAdapterHelperExtensions.kt new file mode 100644 index 000000000..4c796fa3a --- /dev/null +++ b/twidere/src/main/kotlin/android/arch/paging/PagedListAdapterHelperExtensions.kt @@ -0,0 +1,26 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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 . + */ + +package android.arch.paging + +fun PagedListAdapterHelper.setPagedListListener(listener: ((list: PagedList?) -> Unit)?) { + mListener = if (listener != null) PagedListAdapterHelper.PagedListListener { pagedList -> + listener(pagedList) + } else null +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt index 34b959314..65da65e11 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableActivitiesAdapter.kt @@ -22,6 +22,7 @@ package org.mariotaku.twidere.adapter import android.annotation.SuppressLint import android.arch.paging.PagedList import android.arch.paging.PagedListAdapterHelper +import android.arch.paging.setPagedListListener import android.content.Context import android.support.v7.recyclerview.extensions.ListAdapterConfig import android.support.v7.widget.RecyclerView @@ -44,7 +45,11 @@ import org.mariotaku.twidere.annotation.TimelineStyle import org.mariotaku.twidere.constant.newDocumentApiKey import org.mariotaku.twidere.exception.UnsupportedCountIndexException import org.mariotaku.twidere.extension.model.activityStatus -import org.mariotaku.twidere.model.* +import org.mariotaku.twidere.model.ItemCounts +import org.mariotaku.twidere.model.ObjectId +import org.mariotaku.twidere.model.ParcelableActivity +import org.mariotaku.twidere.model.ParcelableMedia +import org.mariotaku.twidere.model.placeholder.ParcelableActivityPlaceholder import org.mariotaku.twidere.util.IntentUtils import org.mariotaku.twidere.util.OnLinkClickHandler import org.mariotaku.twidere.util.TwidereLinkify @@ -119,6 +124,12 @@ class ParcelableActivitiesAdapter( var activityClickListener: ActivityAdapterListener? = null + var pagedListListener: ((list: PagedList?) -> Unit)? = null + set(value) { + field = value + pagedActivitiesHelper.setPagedListListener(value) + } + private val inflater = LayoutInflater.from(context) private val twidereLinkify = TwidereLinkify(OnLinkClickHandler(context, null, preferences)) private val statusAdapterDelegate = DummyItemAdapter(context, twidereLinkify, this, requestManager) @@ -400,18 +411,6 @@ class ParcelableActivitiesAdapter( } } - object ParcelableActivityPlaceholder : ParcelableActivity() { - init { - id = "none" - account_key = UserKey.INVALID - user_key = UserKey.INVALID - } - - override fun hashCode(): Int { - return -1 - } - } - companion object { const val ITEM_VIEW_TYPE_STUB = 0 const val ITEM_VIEW_TYPE_GAP = 1 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableStatusesAdapter.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableStatusesAdapter.kt index a6fa91cbb..c7e62afec 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableStatusesAdapter.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/adapter/ParcelableStatusesAdapter.kt @@ -21,6 +21,7 @@ package org.mariotaku.twidere.adapter import android.arch.paging.PagedList import android.arch.paging.PagedListAdapterHelper +import android.arch.paging.setPagedListListener import android.content.Context import android.support.v4.widget.Space import android.support.v7.recyclerview.extensions.ListAdapterConfig @@ -99,6 +100,20 @@ class ParcelableStatusesAdapter( override val itemCounts = ItemCounts(5) + override var loadMoreIndicatorPosition: Int + get() = super.loadMoreIndicatorPosition + set(value) { + super.loadMoreIndicatorPosition = value + updateItemCounts() + } + + override var loadMoreSupportedPosition: Int + get() = super.loadMoreSupportedPosition + set(value) { + super.loadMoreSupportedPosition = value + updateItemCounts() + } + var isShowInReplyTo: Boolean = false set(value) { if (field == value) return @@ -134,18 +149,10 @@ class ParcelableStatusesAdapter( val statusStartIndex: Int get() = getItemStartPosition(ITEM_INDEX_STATUS) - override var loadMoreIndicatorPosition: Int - get() = super.loadMoreIndicatorPosition + var pagedListListener: ((list: PagedList?) -> Unit)? = null set(value) { - super.loadMoreIndicatorPosition = value - updateItemCounts() - } - - override var loadMoreSupportedPosition: Int - get() = super.loadMoreSupportedPosition - set(value) { - super.loadMoreSupportedPosition = value - updateItemCounts() + field = value + pagedStatusesHelper.setPagedListListener(value) } private val inflater: LayoutInflater = LayoutInflater.from(context) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/activities/AbsActivitiesFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/activities/AbsActivitiesFragment.kt index a1c95db32..d39fd3e6c 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/activities/AbsActivitiesFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/activities/AbsActivitiesFragment.kt @@ -60,7 +60,9 @@ import org.mariotaku.twidere.data.processor.DataSourceItemProcessor import org.mariotaku.twidere.extension.model.activityStatus import org.mariotaku.twidere.extension.queryOne import org.mariotaku.twidere.extension.showContextMenuForChild +import org.mariotaku.twidere.extension.view.PositionWithOffset import org.mariotaku.twidere.extension.view.firstVisibleItemPosition +import org.mariotaku.twidere.extension.view.firstVisibleItemPositionWithOffset import org.mariotaku.twidere.extension.view.lastVisibleItemPosition import org.mariotaku.twidere.fragment.AbsContentRecyclerViewFragment import org.mariotaku.twidere.fragment.timeline.AbsTimelineFragment @@ -82,6 +84,7 @@ import org.mariotaku.twidere.view.ExtendedRecyclerView import org.mariotaku.twidere.view.holder.ActivityTitleSummaryViewHolder import org.mariotaku.twidere.view.holder.GapViewHolder import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder +import java.util.concurrent.atomic.AtomicReference abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment() { @@ -125,12 +128,15 @@ abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment = AtomicReference() private var dataController: ExtendedPagedListProvider.DataController? = null override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) registerForContextMenu(recyclerView) adapter.activityClickListener = ActivityClickHandler() + adapter.pagedListListener = this::onPagedListChanged adapter.loadMoreSupportedPosition = if (isStandalone) { LoadMorePosition.NONE } else { @@ -235,26 +241,7 @@ abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment - SinceMaxPagination.maxId(maxIds[idx], maxSortIds[idx]) - } - } - - override val tabId: Long - get() = this@AbsActivitiesFragment.tabId - - }) - if (!started) return - super.onLoadMoreContents(position) + // No-op } override fun scrollToPositionWithOffset(position: Int, offset: Int) { @@ -269,6 +256,9 @@ abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment?) { - val firstVisiblePosition = layoutManager.firstVisibleItemPosition + val firstVisiblePosition = layoutManager.firstVisibleItemPositionWithOffset adapter.showAccountsColor = accountKeys.size > 1 adapter.activities = data when { @@ -299,12 +289,15 @@ abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment?) { + val firstVisiblePosition = positionBackup.getAndSet(null) ?: return + if (firstVisiblePosition.position == 0 && !preferences[readFromBottomKey]) { + scrollToPositionWithOffset(0, 0) + } else { + scrollToPositionWithOffset(firstVisiblePosition.position, firstVisiblePosition.offset) } } @@ -533,6 +526,31 @@ abstract class AbsActivitiesFragment : AbsContentRecyclerViewFragment() { + override fun onItemAtEndLoaded(itemAtEnd: ParcelableStatus) { + val started = getActivities(object : ContentRefreshParam { + override val accountKeys by lazy { + this@AbsActivitiesFragment.accountKeys + } + override val pagination by lazy { + val keys = accountKeys.toNulls() + val maxIds = DataStoreUtils.getRefreshOldestActivityMaxPositions(context!!, contentUri, keys) + val maxSortIds = DataStoreUtils.getRefreshOldestActivityMaxSortPositions(context!!, contentUri, keys) + return@lazy Array(keys.size) { idx -> + SinceMaxPagination.maxId(maxIds[idx], maxSortIds[idx]) + } + } + + override val tabId: Long + get() = this@AbsActivitiesFragment.tabId + + }) + if (started) { + adapter.loadMoreIndicatorPosition = LoadMorePosition.END + } + } + } + companion object { val activityColumnsLite = Activities.COLUMNS - arrayOf(Activities.SOURCES, Activities.TARGETS, Activities.TARGET_OBJECTS, Activities.MENTIONS_JSON, Activities.CARD, diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/timeline/AbsTimelineFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/timeline/AbsTimelineFragment.kt index fced853ad..b0e7d4835 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/timeline/AbsTimelineFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/timeline/AbsTimelineFragment.kt @@ -70,6 +70,7 @@ import org.mariotaku.twidere.data.fetcher.StatusesFetcher import org.mariotaku.twidere.extension.* import org.mariotaku.twidere.extension.adapter.removeStatuses import org.mariotaku.twidere.extension.data.observe +import org.mariotaku.twidere.extension.view.PositionWithOffset import org.mariotaku.twidere.extension.view.firstVisibleItemPosition import org.mariotaku.twidere.extension.view.firstVisibleItemPositionWithOffset import org.mariotaku.twidere.extension.view.lastVisibleItemPosition @@ -99,6 +100,7 @@ import org.mariotaku.twidere.view.holder.GapViewHolder import org.mariotaku.twidere.view.holder.TimelineFilterHeaderViewHolder import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder import org.mariotaku.twidere.view.holder.status.StatusViewHolder +import java.util.concurrent.atomic.AtomicReference abstract class AbsTimelineFragment : AbsContentRecyclerViewFragment(), IFloatingActionButtonFragment { @@ -154,12 +156,14 @@ abstract class AbsTimelineFragment : AbsContentRecyclerViewFragment = AtomicReference() private var dataController: ExtendedPagedListProvider.DataController? = null override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) registerForContextMenu(recyclerView) adapter.statusClickListener = StatusClickHandler() + adapter.pagedListListener = this::onPagedListChanged adapter.loadMoreSupportedPosition = if (isStandalone) { LoadMorePosition.NONE } else { @@ -285,6 +289,9 @@ abstract class AbsTimelineFragment : AbsContentRecyclerViewFragment?) { val firstVisiblePosition = layoutManager.firstVisibleItemPositionWithOffset adapter.showAccountsColor = accountKeys.size > 1 @@ -331,18 +337,15 @@ abstract class AbsTimelineFragment : AbsContentRecyclerViewFragment?) { + val firstVisiblePosition = positionBackup.getAndSet(null) ?: return if (firstVisiblePosition.position == 0 && !preferences[readFromBottomKey]) { - val weakThis by weak(this) - recyclerView.post { - val f = weakThis?.takeIf { !it.isDetached && it.view != null } ?: return@post - f.scrollToStart() - } + scrollToPositionWithOffset(0, 0) } else { - val lm = loaderManager - if (lm is LinearLayoutManager) { - lm.scrollToPositionWithOffset(firstVisiblePosition.position, firstVisiblePosition.offset) - } + scrollToPositionWithOffset(firstVisiblePosition.position, firstVisiblePosition.offset) } } @@ -400,7 +403,7 @@ abstract class AbsTimelineFragment : AbsContentRecyclerViewFragment + * + * 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 . + */ + +package org.mariotaku.twidere.model.placeholder + +import org.mariotaku.twidere.model.ParcelableActivity +import org.mariotaku.twidere.model.UserKey + +object ParcelableActivityPlaceholder : ParcelableActivity() { + init { + id = "none" + account_key = UserKey.INVALID + user_key = UserKey.INVALID + } + + override fun hashCode(): Int { + return -1 + } +} \ No newline at end of file