diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/dao/clip/ClipDao.kt b/composeApp/src/commonMain/kotlin/com/clipevery/dao/clip/ClipDao.kt index 070cf9646..4d6a700e0 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/dao/clip/ClipDao.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/dao/clip/ClipDao.kt @@ -15,8 +15,10 @@ interface ClipDao { fun getClipData(appInstanceId: String? = null, limit: Int): RealmResults - fun getClipData(appInstanceId: String?, - limit: Int, - createTime: RealmInstant, - excludeClipId: List): RealmResults + fun getClipDataGreaterThan(appInstanceId: String? = null, + createTime: RealmInstant): RealmResults + + fun getClipDataLessThan(appInstanceId: String? = null, + limit: Int, + createTime: RealmInstant): RealmResults } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewsView.kt b/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewsView.kt index 4e5bd9efc..4ae9c97f2 100644 --- a/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewsView.kt +++ b/composeApp/src/commonMain/kotlin/com/clipevery/ui/clip/ClipPreviewsView.kt @@ -33,30 +33,73 @@ import androidx.compose.ui.unit.dp import com.clipevery.LocalKoinApplication import com.clipevery.dao.clip.ClipDao import com.clipevery.dao.clip.ClipData +import io.realm.kotlin.notifications.ResultsChange +import io.realm.kotlin.notifications.UpdatedResults +import io.realm.kotlin.query.RealmResults import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.launch +val clipDataComparator = compareByDescending { it.createTime } + .thenBy{ it.appInstanceId } + .thenBy { it.clipId } + @Composable fun ClipPreviewsView() { val current = LocalKoinApplication.current val clipDao = current.koin.get() - val clipDataList: List = clipDao.getClipData(limit = 20) + val clipDataList: RealmResults = clipDao.getClipData(limit = 20) val listState = rememberLazyListState() var isScrolling by remember { mutableStateOf(false) } var scrollJob: Job? by remember { mutableStateOf(null) } val coroutineScope = rememberCoroutineScope() val rememberClipDataList = remember { mutableStateListOf().apply { - addAll(clipDataList) + addAll(clipDataList.sortedWith(clipDataComparator)) } } + LaunchedEffect(Unit) { + val clipDatasFlow = clipDao.getClipData(limit = 20).asFlow() + clipDatasFlow.collect { changes: ResultsChange -> + when (changes) { + is UpdatedResults -> { + changes.insertions + changes.insertionRanges + val firstClipData: ClipData? = rememberClipDataList.firstOrNull() + + firstClipData?.let { + val newClipDataList = clipDao.getClipDataGreaterThan(createTime = it.createTime) + for (clipData in newClipDataList.reversed()) { + if (clipDataComparator.compare(clipData, firstClipData) < 0) { + rememberClipDataList.add(0, clipData) + } + } + } ?: run { + val newClipDataList = clipDao.getClipData(limit = 20) + rememberClipDataList.addAll(newClipDataList.sortedWith(clipDataComparator)) + } + } + else -> { + // types other than UpdatedResults are not changes -- ignore them + } + } + } + } + LaunchedEffect(listState) { snapshotFlow { listState.layoutInfo.visibleItemsInfo } .collect { visibleItems -> if (visibleItems.isNotEmpty() && visibleItems.last().index == rememberClipDataList.size - 1) { - // todo loadMoreItems() + val lastClipData: ClipData? = rememberClipDataList.lastOrNull() + lastClipData?.let { + val newClipDataList = clipDao.getClipDataLessThan(createTime = it.createTime, limit = 20) + for (clipData in newClipDataList) { + if (clipDataComparator.compare(clipData, lastClipData) > 0) { + rememberClipDataList.add(clipData) + } + } + } } isScrolling = true scrollJob?.cancel() diff --git a/composeApp/src/desktopMain/kotlin/com/clipevery/dao/clip/ClipRealm.kt b/composeApp/src/desktopMain/kotlin/com/clipevery/dao/clip/ClipRealm.kt index 30715c252..623779cc9 100644 --- a/composeApp/src/desktopMain/kotlin/com/clipevery/dao/clip/ClipRealm.kt +++ b/composeApp/src/desktopMain/kotlin/com/clipevery/dao/clip/ClipRealm.kt @@ -72,16 +72,26 @@ class ClipRealm(private val realm: Realm): ClipDao { return query.sort("createTime", Sort.DESCENDING).limit(limit).find() } - override fun getClipData( + override fun getClipDataGreaterThan( + appInstanceId: String?, + createTime: RealmInstant + ): RealmResults { + var query = appInstanceId?.let { + realm.query(ClipData::class).query("appInstanceId == $0", appInstanceId) + } ?: realm.query(ClipData::class) + query = query.query("createTime >= $0", createTime) + return query.sort("createTime", Sort.DESCENDING).find() + } + + override fun getClipDataLessThan( appInstanceId: String?, limit: Int, - createTime: RealmInstant, - excludeClipId: List + createTime: RealmInstant ): RealmResults { var query = appInstanceId?.let { realm.query(ClipData::class).query("appInstanceId == $0", appInstanceId) } ?: realm.query(ClipData::class) - query = query.query("clipId not in $0", excludeClipId) + query = query.query("createTime <= $0", createTime) return query.sort("createTime", Sort.DESCENDING).limit(limit).find() } } \ No newline at end of file