Skip to content

Commit ca529c1

Browse files
committed
Add design doc
Signed-off-by: mramotar_dbx <[email protected]>
1 parent d4501dc commit ca529c1

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed

paging/docs/design_doc.md

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
# Paging Technical Design Doc
2+
3+
## 1. Motivations
4+
5+
Powerful and extensible solution for paging in KMP projects, under the Mobile Native Foundation.
6+
Address these Android Paging limitations:
7+
8+
- [x] Seamless integration with Store and Mutable Store
9+
- [x] Local mutations and streaming of child items within the list of paging items
10+
- [x] Custom reducer, middleware, and post-reducer effects
11+
12+
## 2. Overview
13+
14+
[//]: # (TODO: Arch diagram)
15+
16+
Modular and flexible architecture. Using builder, reducer, middleware, and post-reducer effect patterns. Unidirectional
17+
data flow. The `Pager` is the main component. Actions are dispatched through the `Pager`. The `PagerBuilder` creates
18+
the `Pager`.
19+
It allows
20+
configuration of the paging behavior. The `PagingSource` defines the data loading logic. The `PageFetchingStrategy`
21+
determines when to fetch the next page.
22+
The `PageAggregatingStrategy` combines loaded pages into a single list. The `PagingReducer` handles state changes based
23+
on actions. When an action is dispatched, it goes through the middleware
24+
pipeline. The middleware can modify the action. The reducer then updates the
25+
state based on the action. After the reducer, we invoke post-reducer effects associated with the action and new state.
26+
The updated state is sent back the `Pager` and emitted to the UI.
27+
28+
## 3. The Actual Design
29+
30+
### 3.1 Key Components
31+
32+
- `Pager`: The main entry point, responsible for coordinating the paging process and providing access to the paging
33+
state and data.
34+
- `PagingSource`: Defines the data source and loading logic for paged data.
35+
- `PagingState`: Represents the current state of the paging data, including loaded pages, errors, and loading status.
36+
- `PagingAction`: Defines the actions that can be dispatched to modify the paging state.
37+
- `PagingReducer`: Reduces the paging state based on dispatched actions.
38+
- `PagingMiddleware`: Intercepts and modifies paging actions before they reach the reducer.
39+
- `PostReducerEffect`: Performs side effects after reducing the paging state.
40+
- `PageFetchingStrategy`: Determines when to fetch the next page of data.
41+
- `PageAggregatingStrategy`: Aggregates loaded pages into a single list.
42+
- `MutablePagingBuffer`: Efficiently stores and retrieves paging data.
43+
- `JobCoordinator`: Coordinates the execution of paging-related jobs.
44+
- `QueueManager`: Manages the queue of pages to be loaded.
45+
- `PagingStreamProvider`: Provides a stream of paging data.
46+
- `PagingKeyFactory`: Creates keys for paging data.
47+
- `PagingConfig`: Configures the paging behavior.
48+
- `ErrorHandlingStrategy`: Defines how to handle errors during the paging process.
49+
- `Logger`: Logs paging-related events and actions.
50+
51+
### 3.2 Customizations
52+
53+
We are providing many extension points and customization options to tailor the paging behavior. Some of the key
54+
customization points:
55+
56+
- `PagingSource`: Developers can implement their own `PagingSource` to define how paged data is loaded from the data
57+
source. This allows for integration with different data sources and loading mechanisms.
58+
- `PagingMiddleware`: Custom `PagingMiddleware` can be implemented to intercept and modify paging actions before they
59+
reach the reducer. This enables preprocessing, logging, or any other custom logic.
60+
- `PagingReducer`: The `PagingReducer` can be customized to define how the paging state is reduced based on dispatched
61+
actions. This allows for fine-grained control over the paging state transitions.
62+
- `PostReducerEffect`: Custom `PostReducerEffect` instances can be configured to perform side effects after reducing the
63+
paging state. This is useful for triggering UI updates, analytics events, or any other necessary actions.
64+
- `PageFetchingStrategy`: Developers can implement their own `PageFetchingStrategy` to determine when to fetch the next
65+
page of data based on the current state and configuration. This allows for customizing the prefetching behavior.
66+
- `PageAggregatingStrategy`: Custom `PageAggregatingStrategy` implementations can be provided to define how loaded pages
67+
are aggregated into a single list. This enables different aggregation strategies based on the specific requirements of
68+
the application.
69+
- `ErrorHandlingStrategy`: Developers can implement their own `ErrorHandlingStrategy` to define how errors during the
70+
paging process are handled. This allows for custom error handling, retry mechanisms, or fallback behaviors.
71+
72+
### 3.3 Data Flow
73+
74+
[//]: # (TODO: Data flow diagram)
75+
76+
Unidirectional data flow. Main steps:
77+
78+
1. `Pager` is configured using `PagerBuilder` and provided an initial key, flow of anchor position, and paging config.
79+
2. `Pager` subscribes to the `PagingSource` to receive paging data updates.
80+
3. When a `PagingAction` is dispatched, it goes through the configured `PagingMiddleware` chain. This enables
81+
interception and modification of the action.
82+
4. The modified action reaches the `PagingReducer`, which reduces the current `PagingState` based on the action and
83+
returns a new `PagingState`.
84+
5. After reduction, any configured `PostReducerEffect` instances are executed, enabling side effects to be performed
85+
based on the new `PagingState`.
86+
6. `Pager` updates `PagingStateManager` with the new `PagingState`.
87+
7. `PageFetchingStrategy` determines when to fetch the next page of data based on the `PagingConfig` and
88+
current `PagingState`.
89+
8. When a new page needs to be fetched, `QueueManager` enqueues the page key, and the `JobCoordinator` coordinates the
90+
execution of the paging job.
91+
9. `PagingSource` loads the requested page and emits the loaded data through the `PagingStreamProvider`.
92+
10. The loaded page is stored in the `MutablePagingBuffer` for efficient retrieval and aggregation.
93+
11. The `PageAggregatingStrategy` aggregates the loaded pages into a single list, which is then emitted through
94+
the `Pager` for consumption by the UI.
95+
96+
## 4. Sample Code
97+
98+
Configuring the Pager using `PagerBuilder`:
99+
100+
```kotlin
101+
val pager =
102+
PagerBuilder<Int, CollectionKey, SingleData, CustomAction, CustomError>(
103+
initialKey = CollectionKey(0),
104+
anchorPosition = anchorPositionFlow,
105+
pagingConfig = pagingConfig
106+
)
107+
.dispatcher(
108+
logger = DefaultLogger(),
109+
) {
110+
111+
// Use the default reducer
112+
defaultReducer {
113+
errorHandlingStrategy(ErrorHandlingStrategy.PassThrough)
114+
pagingBufferMaxSize(100)
115+
}
116+
117+
middlewares(
118+
listOf(
119+
// Add custom middleware
120+
)
121+
)
122+
123+
// Add custom post reducer effects
124+
postReducerEffect<MyPagingState, MyPagingAction>(
125+
state = MyPagingState::class,
126+
action = MyPagingAction::class,
127+
effect = MyPostReducerEffect
128+
)
129+
130+
// Use the default post reducer effects
131+
defaultPostReducerEffects(pagingSource = pagingSource)
132+
}
133+
134+
.build()
135+
```
136+
137+
Observing the paging state and dispatching actions:
138+
139+
```kotlin
140+
pager.state.collect { state ->
141+
when (state) {
142+
is PagingState.Data.Idle -> {
143+
// Update UI with loaded data and provide dispatch callback
144+
DataView(pagingItems = state.data) { action: PagingAction.User ->
145+
pager.dispatch(action)
146+
}
147+
}
148+
is PagingState.LoadingInitial -> {
149+
// Show loading indicator
150+
InitialLoadingView()
151+
}
152+
is PagingState.Error -> {
153+
// Handle error state and provide dispatch callback
154+
InitialErrorViewCoordinator(errorState = state) { action: PagingAction.User ->
155+
pager.dispatch(action)
156+
}
157+
}
158+
}
159+
}
160+
```

0 commit comments

Comments
 (0)