Skip to content

Commit 274b347

Browse files
Merge pull request #47 from raheemadamboev/1.2.3
1.2.3
2 parents ce120bb + 4180915 commit 274b347

File tree

11 files changed

+101
-59
lines changed

11 files changed

+101
-59
lines changed

app/build.gradle.kts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ android {
1818
applicationId = "xyz.teamgravity.todo"
1919
minSdk = libs.versions.sdk.min.get().toInt()
2020
targetSdk = libs.versions.sdk.target.get().toInt()
21-
versionCode = 13
22-
versionName = "1.2.2"
21+
versionCode = 14
22+
versionName = "1.2.3"
2323
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2424

2525
vectorDrawables {
@@ -100,6 +100,9 @@ dependencies {
100100
// compose hilt
101101
implementation(libs.compose.hilt)
102102

103+
// compose paging
104+
implementation(libs.compose.paging)
105+
103106
// core
104107
implementation(libs.core)
105108

@@ -126,6 +129,7 @@ dependencies {
126129
// room
127130
implementation(libs.room)
128131
implementation(libs.room.ktx)
132+
implementation(libs.room.paging)
129133
ksp(libs.room.compiler)
130134

131135
// destinations
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package xyz.teamgravity.todo.core.constant
2+
3+
object PagingConst {
4+
const val PAGE_SIZE = 70
5+
const val PREFETCH_DISTANCE = PAGE_SIZE / 2
6+
const val MAX_SIZE = PAGE_SIZE * 3
7+
const val ENABLE_PLACEHOLDERS = false
8+
}

app/src/main/java/xyz/teamgravity/todo/data/local/todo/dao/TodoDao.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
package xyz.teamgravity.todo.data.local.todo.dao
22

3+
import androidx.paging.PagingSource
34
import androidx.room.Dao
45
import androidx.room.Delete
56
import androidx.room.Insert
67
import androidx.room.OnConflictStrategy
78
import androidx.room.Query
89
import androidx.room.Update
9-
import kotlinx.coroutines.flow.Flow
1010
import xyz.teamgravity.todo.core.constant.TodoSort
1111
import xyz.teamgravity.todo.data.local.todo.constant.TodoDatabaseConst.TABLE_TODO
1212
import xyz.teamgravity.todo.data.local.todo.entity.TodoEntity
@@ -42,14 +42,14 @@ interface TodoDao {
4242
suspend fun deleteAllTodo()
4343

4444
///////////////////////////////////////////////////////////////////////////
45-
// GET
45+
// Get
4646
///////////////////////////////////////////////////////////////////////////
4747

4848
fun getTodos(
4949
query: String,
5050
hideCompleted: Boolean,
5151
sorting: TodoSort
52-
): Flow<List<TodoEntity>> {
52+
): PagingSource<Int, TodoEntity> {
5353
return when (sorting) {
5454
TodoSort.Name -> getTodosSortedByName(
5555
query = query,
@@ -67,11 +67,11 @@ interface TodoDao {
6767
fun getTodosSortedByName(
6868
query: String,
6969
hideCompleted: Boolean
70-
): Flow<List<TodoEntity>>
70+
): PagingSource<Int, TodoEntity>
7171

7272
@Query("SELECT * FROM $TABLE_TODO WHERE (completed != :hideCompleted OR completed = 0) AND name LIKE '%' || :query || '%' ORDER BY important DESC, timestamp ASC")
7373
fun getTodosSortedByDate(
7474
query: String,
7575
hideCompleted: Boolean
76-
): Flow<List<TodoEntity>>
76+
): PagingSource<Int, TodoEntity>
7777
}

app/src/main/java/xyz/teamgravity/todo/data/repository/TodoRepository.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package xyz.teamgravity.todo.data.repository
22

3+
import androidx.paging.Pager
4+
import androidx.paging.PagingConfig
5+
import androidx.paging.PagingData
6+
import androidx.paging.map
37
import kotlinx.coroutines.Dispatchers
48
import kotlinx.coroutines.flow.Flow
59
import kotlinx.coroutines.flow.map
@@ -11,7 +15,8 @@ import xyz.teamgravity.todo.data.mapper.toModel
1115
import xyz.teamgravity.todo.data.model.TodoModel
1216

1317
class TodoRepository(
14-
private val dao: TodoDao
18+
private val dao: TodoDao,
19+
private val config: PagingConfig
1520
) {
1621

1722
///////////////////////////////////////////////////////////////////////////
@@ -64,12 +69,17 @@ class TodoRepository(
6469
query: String,
6570
hideCompleted: Boolean,
6671
sorting: TodoSort
67-
): Flow<List<TodoModel>> {
68-
return dao.getTodos(
69-
query = query,
70-
hideCompleted = hideCompleted,
71-
sorting = sorting
72-
).map { entities ->
72+
): Flow<PagingData<TodoModel>> {
73+
return Pager(
74+
config = config,
75+
pagingSourceFactory = {
76+
dao.getTodos(
77+
query = query,
78+
hideCompleted = hideCompleted,
79+
sorting = sorting
80+
)
81+
}
82+
).flow.map { entities ->
7383
entities.map { entity ->
7484
entity.toModel()
7585
}

app/src/main/java/xyz/teamgravity/todo/injection/provide/ApplicationModule.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package xyz.teamgravity.todo.injection.provide
22

33
import android.app.Application
4+
import androidx.paging.PagingConfig
45
import androidx.room.Room
56
import dagger.Module
67
import dagger.Provides
@@ -14,6 +15,7 @@ import xyz.teamgravity.coresdkandroid.crypto.CryptoManager
1415
import xyz.teamgravity.coresdkandroid.preferences.Preferences
1516
import xyz.teamgravity.coresdkandroid.review.ReviewManager
1617
import xyz.teamgravity.coresdkandroid.update.UpdateManager
18+
import xyz.teamgravity.todo.core.constant.PagingConst
1719
import xyz.teamgravity.todo.data.local.preferences.AppPreferences
1820
import xyz.teamgravity.todo.data.local.todo.callback.TodoCallback
1921
import xyz.teamgravity.todo.data.local.todo.constant.TodoDatabaseConst
@@ -64,7 +66,22 @@ object ApplicationModule {
6466

6567
@Provides
6668
@Singleton
67-
fun provideTodoRepository(todoDao: TodoDao): TodoRepository = TodoRepository(todoDao)
69+
fun providePagingConfig(): PagingConfig = PagingConfig(
70+
pageSize = PagingConst.PAGE_SIZE,
71+
prefetchDistance = PagingConst.PREFETCH_DISTANCE,
72+
maxSize = PagingConst.MAX_SIZE,
73+
enablePlaceholders = PagingConst.ENABLE_PLACEHOLDERS
74+
)
75+
76+
@Provides
77+
@Singleton
78+
fun provideTodoRepository(
79+
todoDao: TodoDao,
80+
pagingConfig: PagingConfig
81+
): TodoRepository = TodoRepository(
82+
dao = todoDao,
83+
config = pagingConfig
84+
)
6885

6986
@Provides
7087
@Singleton

app/src/main/java/xyz/teamgravity/todo/presentation/activity/Main.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class Main : ComponentActivity() {
2020
installSplashScreen()
2121
super.onCreate(savedInstanceState)
2222
enableEdgeToEdge()
23-
val intent = intent
23+
val intent = if (savedInstanceState == null) intent else null
2424
setContent {
2525
TodoTheme {
2626
Navigation(intent)

app/src/main/java/xyz/teamgravity/todo/presentation/screen/todo/add/TodoAddViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class TodoAddViewModel @Inject constructor(
6161
}
6262

6363
///////////////////////////////////////////////////////////////////////////
64-
// MISC
64+
// Misc
6565
///////////////////////////////////////////////////////////////////////////
6666

6767
sealed interface TodoAddEvent {

app/src/main/java/xyz/teamgravity/todo/presentation/screen/todo/edit/TodoEditViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class TodoEditViewModel @Inject constructor(
7070
}
7171

7272
///////////////////////////////////////////////////////////////////////////
73-
// MISC
73+
// Misc
7474
///////////////////////////////////////////////////////////////////////////
7575

7676
sealed interface TodoEditEvent {

app/src/main/java/xyz/teamgravity/todo/presentation/screen/todo/list/TodoListScreen.kt

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.WindowInsets
77
import androidx.compose.foundation.layout.fillMaxSize
88
import androidx.compose.foundation.layout.safeDrawing
99
import androidx.compose.foundation.lazy.LazyColumn
10-
import androidx.compose.foundation.lazy.items
1110
import androidx.compose.material.icons.Icons
1211
import androidx.compose.material.icons.filled.Add
1312
import androidx.compose.material.icons.filled.Search
@@ -26,6 +25,9 @@ import androidx.hilt.navigation.compose.hiltViewModel
2625
import androidx.lifecycle.Lifecycle
2726
import androidx.lifecycle.compose.LifecycleEventEffect
2827
import androidx.lifecycle.compose.collectAsStateWithLifecycle
28+
import androidx.paging.compose.collectAsLazyPagingItems
29+
import androidx.paging.compose.itemContentType
30+
import androidx.paging.compose.itemKey
2931
import com.ramcosta.composedestinations.annotation.Destination
3032
import com.ramcosta.composedestinations.generated.destinations.AboutScreenDestination
3133
import com.ramcosta.composedestinations.generated.destinations.SupportScreenDestination
@@ -59,6 +61,7 @@ fun TodoListScreen(
5961
) {
6062
val context = LocalContext.current
6163
val activity = LocalActivity.current
64+
val todos = viewmodel.todos.collectAsLazyPagingItems()
6265
val query by viewmodel.query.collectAsStateWithLifecycle()
6366
val updateLauncher = rememberLauncherForActivityResult(
6467
contract = ActivityResultContracts.StartIntentSenderForResult(),
@@ -182,17 +185,25 @@ fun TodoListScreen(
182185
modifier = Modifier.fillMaxSize()
183186
) {
184187
items(
185-
items = viewmodel.todos,
186-
key = { it.id }
187-
) { todo ->
188-
CardTodo(
189-
todo = todo,
190-
onClick = {
191-
navigator.navigate(TodoEditScreenDestination(it))
192-
},
193-
onCheckedChange = viewmodel::onTodoChecked,
194-
onDismiss = viewmodel::onTodoDelete
195-
)
188+
count = todos.itemCount,
189+
key = todos.itemKey(
190+
key = { todo ->
191+
todo.id
192+
}
193+
),
194+
contentType = todos.itemContentType()
195+
) { index ->
196+
val todo = todos[index]
197+
if (todo != null) {
198+
CardTodo(
199+
todo = todo,
200+
onClick = {
201+
navigator.navigate(TodoEditScreenDestination(it))
202+
},
203+
onCheckedChange = viewmodel::onTodoChecked,
204+
onDismiss = viewmodel::onTodoDelete
205+
)
206+
}
196207
}
197208
}
198209
if (viewmodel.deleteCompletedShown) {

app/src/main/java/xyz/teamgravity/todo/presentation/screen/todo/list/TodoListViewModel.kt

Lines changed: 16 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,15 @@ import androidx.compose.runtime.mutableStateOf
88
import androidx.compose.runtime.setValue
99
import androidx.lifecycle.ViewModel
1010
import androidx.lifecycle.viewModelScope
11+
import androidx.paging.PagingData
12+
import androidx.paging.cachedIn
1113
import dagger.hilt.android.lifecycle.HiltViewModel
12-
import kotlinx.collections.immutable.ImmutableList
13-
import kotlinx.collections.immutable.persistentListOf
14-
import kotlinx.collections.immutable.toImmutableList
1514
import kotlinx.coroutines.channels.Channel
1615
import kotlinx.coroutines.delay
1716
import kotlinx.coroutines.flow.Flow
1817
import kotlinx.coroutines.flow.MutableStateFlow
1918
import kotlinx.coroutines.flow.StateFlow
2019
import kotlinx.coroutines.flow.asStateFlow
21-
import kotlinx.coroutines.flow.collectLatest
2220
import kotlinx.coroutines.flow.combine
2321
import kotlinx.coroutines.flow.flatMapLatest
2422
import kotlinx.coroutines.flow.receiveAsFlow
@@ -44,9 +42,6 @@ class TodoListViewModel @Inject constructor(
4442
private val _query = MutableStateFlow("")
4543
val query: StateFlow<String> = _query.asStateFlow()
4644

47-
var todos: ImmutableList<TodoModel> by mutableStateOf(persistentListOf())
48-
private set
49-
5045
var searchExpanded: Boolean by mutableStateOf(false)
5146
private set
5247

@@ -77,6 +72,19 @@ class TodoListViewModel @Inject constructor(
7772
var deleteAllShown: Boolean by mutableStateOf(false)
7873
private set
7974

75+
val todos: Flow<PagingData<TodoModel>> =
76+
combine(query, preferences.getSorting(), preferences.getHideCompleted()) { query, sorting, hideCompleted ->
77+
Triple(query, sorting, hideCompleted)
78+
}.flatMapLatest { (query, sorting, hideCompleted) ->
79+
this@TodoListViewModel.hideCompleted = hideCompleted
80+
this@TodoListViewModel.sorting = sorting
81+
repository.getTodos(
82+
query = query,
83+
hideCompleted = hideCompleted,
84+
sorting = sorting
85+
).cachedIn(viewModelScope)
86+
}
87+
8088
private val _event = Channel<TodoListEvent>()
8189
val event: Flow<TodoListEvent> = _event.receiveAsFlow()
8290

@@ -90,7 +98,6 @@ class TodoListViewModel @Inject constructor(
9098
private fun observe() {
9199
observeReviewEvent()
92100
observeUpdateEvent()
93-
observeQueryAndPreferences()
94101
}
95102

96103
private fun monitor() {
@@ -138,24 +145,6 @@ class TodoListViewModel @Inject constructor(
138145
}
139146
}
140147

141-
private fun observeQueryAndPreferences() {
142-
viewModelScope.launch {
143-
combine(query, preferences.getSorting(), preferences.getHideCompleted()) { query, sorting, hideCompleted ->
144-
Triple(query, sorting, hideCompleted)
145-
}.flatMapLatest { (query, sorting, hideCompleted) ->
146-
this@TodoListViewModel.hideCompleted = hideCompleted
147-
this@TodoListViewModel.sorting = sorting
148-
repository.getTodos(
149-
query = query,
150-
hideCompleted = hideCompleted,
151-
sorting = sorting
152-
)
153-
}.collectLatest { todos ->
154-
this@TodoListViewModel.todos = todos.toImmutableList()
155-
}
156-
}
157-
}
158-
159148
///////////////////////////////////////////////////////////////////////////
160149
// API
161150
///////////////////////////////////////////////////////////////////////////
@@ -325,7 +314,7 @@ class TodoListViewModel @Inject constructor(
325314
}
326315

327316
///////////////////////////////////////////////////////////////////////////
328-
// MISC
317+
// Misc
329318
///////////////////////////////////////////////////////////////////////////
330319

331320
enum class TodoListEvent {

0 commit comments

Comments
 (0)