porting page reducers to new iteration
This commit is contained in:
parent
7a13f530b0
commit
f0e5ae4502
|
@ -1,6 +1,7 @@
|
||||||
package app.dapk.st.core
|
package app.dapk.st.core
|
||||||
|
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class JobBag {
|
class JobBag {
|
||||||
|
|
||||||
|
@ -11,8 +12,17 @@ class JobBag {
|
||||||
jobs[key] = job
|
jobs[key] = job
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun replace(key: KClass<*>, job: Job) {
|
||||||
|
jobs[key.java.canonicalName]?.cancel()
|
||||||
|
jobs[key.java.canonicalName] = job
|
||||||
|
}
|
||||||
|
|
||||||
fun cancel(key: String) {
|
fun cancel(key: String) {
|
||||||
jobs.remove(key)?.cancel()
|
jobs.remove(key)?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun cancel(key: KClass<*>) {
|
||||||
|
jobs.remove(key.java.canonicalName)?.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,32 +4,12 @@ import app.dapk.st.design.components.SpiderPage
|
||||||
import app.dapk.state.*
|
import app.dapk.state.*
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
fun <P : Any> createPageReducer(
|
sealed interface PageAction<out P> : Action {
|
||||||
initialPage: SpiderPage<out P>
|
data class GoTo<P : Any>(val page: SpiderPage<P>) : PageAction<P>
|
||||||
): ReducerFactory<PageContainer<P>> {
|
|
||||||
return createReducer(
|
|
||||||
initialState = PageContainer(
|
|
||||||
page = initialPage
|
|
||||||
),
|
|
||||||
|
|
||||||
change(PageAction.GoTo::class) { action, state ->
|
|
||||||
state.copy(page = action.page as SpiderPage<P>)
|
|
||||||
},
|
|
||||||
|
|
||||||
change(PageAction.UpdatePage::class) { action, state ->
|
|
||||||
val isSamePage = state.page.state::class == action.pageContent::class
|
|
||||||
if (isSamePage) {
|
|
||||||
val updatedPageContent = (state.page as SpiderPage<Any>).copy(state = action.pageContent)
|
|
||||||
state.copy(page = updatedPageContent as SpiderPage<out P>)
|
|
||||||
} else {
|
|
||||||
state
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface PageAction<P> : Action {
|
sealed interface PageStateChange : Action {
|
||||||
data class GoTo<P : Any>(val page: SpiderPage<P>) : PageAction<P>
|
data class ChangePage<P : Any>(val previous: SpiderPage<out P>, val newPage: SpiderPage<out P>) : PageAction<P>
|
||||||
data class UpdatePage<P : Any>(val pageContent: P) : PageAction<P>
|
data class UpdatePage<P : Any>(val pageContent: P) : PageAction<P>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,26 +17,23 @@ data class PageContainer<P>(
|
||||||
val page: SpiderPage<out P>
|
val page: SpiderPage<out P>
|
||||||
)
|
)
|
||||||
|
|
||||||
fun PageContainer<*>.isDifferentPage(page: SpiderPage<*>): Boolean {
|
interface PageReducerScope<P> {
|
||||||
return page::class != this.page::class
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PageReducerScope {
|
|
||||||
fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit)
|
fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit)
|
||||||
|
fun rawPage(): SpiderPage<out P>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PageDispatchScope<P> {
|
interface PageDispatchScope<PC> {
|
||||||
fun ReducerScope<*>.pageDispatch(action: PageAction<P>)
|
fun ReducerScope<*>.pageDispatch(action: PageAction<PC>)
|
||||||
fun getPageState(): P?
|
fun getPageState(): PC?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <P : Any, S : Any> createPageReducer(
|
fun <P : Any, S : Any> createPageReducer(
|
||||||
initialPage: SpiderPage<out P>,
|
initialPage: SpiderPage<out P>,
|
||||||
factory: PageReducerScope.() -> ReducerFactory<S>,
|
factory: PageReducerScope<P>.() -> ReducerFactory<S>,
|
||||||
): ReducerFactory<Combined2<PageContainer<P>, S>> = shareState {
|
): ReducerFactory<Combined2<PageContainer<P>, S>> = shareState {
|
||||||
combineReducers(
|
combineReducers(
|
||||||
createPageReducer(initialPage),
|
createPageReducer(initialPage),
|
||||||
factory(object : PageReducerScope {
|
factory(object : PageReducerScope<P> {
|
||||||
override fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit) {
|
override fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit) {
|
||||||
val currentPage = getSharedState().state1.page.state
|
val currentPage = getSharedState().state1.page.state
|
||||||
if (currentPage::class == page) {
|
if (currentPage::class == page) {
|
||||||
|
@ -73,11 +50,45 @@ fun <P : Any, S : Any> createPageReducer(
|
||||||
block(pageDispatchScope)
|
block(pageDispatchScope)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun rawPage() = getSharedState().state1.page
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified PC : Any> PageReducerScope.withPageContext(crossinline block: PageDispatchScope<PC>.(PC) -> Unit) {
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun <P : Any> createPageReducer(
|
||||||
|
initialPage: SpiderPage<out P>
|
||||||
|
): ReducerFactory<PageContainer<P>> {
|
||||||
|
return createReducer(
|
||||||
|
initialState = PageContainer(
|
||||||
|
page = initialPage
|
||||||
|
),
|
||||||
|
|
||||||
|
async(PageAction.GoTo::class) { action ->
|
||||||
|
val state = getState()
|
||||||
|
if (state.page.state::class != action.page.state::class) {
|
||||||
|
dispatch(PageStateChange.ChangePage(previous = state.page, newPage = action.page))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
change(PageStateChange.ChangePage::class) { action, state ->
|
||||||
|
state.copy(page = action.newPage as SpiderPage<out P>)
|
||||||
|
},
|
||||||
|
|
||||||
|
change(PageStateChange.UpdatePage::class) { action, state ->
|
||||||
|
val isSamePage = state.page.state::class == action.pageContent::class
|
||||||
|
if (isSamePage) {
|
||||||
|
val updatedPageContent = (state.page as SpiderPage<Any>).copy(state = action.pageContent)
|
||||||
|
state.copy(page = updatedPageContent as SpiderPage<out P>)
|
||||||
|
} else {
|
||||||
|
state
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified PC : Any> PageReducerScope<*>.withPageContext(crossinline block: PageDispatchScope<PC>.(PC) -> Unit) {
|
||||||
withPageContent(PC::class) { getPageState()?.let { block(it) } }
|
withPageContent(PC::class) { getPageState()?.let { block(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,15 @@ package app.dapk.st.messenger.gallery.state
|
||||||
import app.dapk.st.core.JobBag
|
import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.page.PageAction
|
import app.dapk.st.core.page.PageAction
|
||||||
import app.dapk.st.core.page.PageContainer
|
import app.dapk.st.core.page.PageStateChange
|
||||||
import app.dapk.st.core.page.isDifferentPage
|
import app.dapk.st.core.page.createPageReducer
|
||||||
|
import app.dapk.st.core.page.withPageContext
|
||||||
import app.dapk.st.design.components.SpiderPage
|
import app.dapk.st.design.components.SpiderPage
|
||||||
import app.dapk.st.messenger.gallery.*
|
import app.dapk.st.messenger.gallery.FetchMediaFoldersUseCase
|
||||||
import app.dapk.state.*
|
import app.dapk.st.messenger.gallery.FetchMediaUseCase
|
||||||
|
import app.dapk.state.async
|
||||||
|
import app.dapk.state.createReducer
|
||||||
|
import app.dapk.state.sideEffect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
fun imageGalleryReducer(
|
fun imageGalleryReducer(
|
||||||
|
@ -15,54 +19,47 @@ fun imageGalleryReducer(
|
||||||
foldersUseCase: FetchMediaFoldersUseCase,
|
foldersUseCase: FetchMediaFoldersUseCase,
|
||||||
fetchMediaUseCase: FetchMediaUseCase,
|
fetchMediaUseCase: FetchMediaUseCase,
|
||||||
jobBag: JobBag,
|
jobBag: JobBag,
|
||||||
) = shareState {
|
) = createPageReducer(
|
||||||
combineReducers(
|
initialPage = SpiderPage<ImageGalleryPage>(
|
||||||
createPageReducer(roomName),
|
|
||||||
createImageGalleryPageReducer(jobBag, foldersUseCase, fetchMediaUseCase),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createPageReducer(roomName: String): ReducerFactory<PageContainer<ImageGalleryPage>> = app.dapk.st.core.page.createPageReducer(
|
|
||||||
initialPage = SpiderPage(
|
|
||||||
route = ImageGalleryPage.Routes.folders,
|
route = ImageGalleryPage.Routes.folders,
|
||||||
label = "Send to $roomName",
|
label = "Send to $roomName",
|
||||||
parent = null,
|
parent = null,
|
||||||
state = ImageGalleryPage.Folders(Lce.Loading())
|
state = ImageGalleryPage.Folders(Lce.Loading())
|
||||||
)
|
),
|
||||||
)
|
factory = {
|
||||||
|
createReducer(
|
||||||
|
initialState = Unit,
|
||||||
|
|
||||||
private fun SharedStateScope<Combined2<PageContainer<ImageGalleryPage>, Unit>>.createImageGalleryPageReducer(
|
async(ImageGalleryActions.Visible::class) {
|
||||||
jobBag: JobBag,
|
jobBag.replace(ImageGalleryPage.Folders::class, coroutineScope.launch {
|
||||||
foldersUseCase: FetchMediaFoldersUseCase,
|
val folders = foldersUseCase.fetchFolders()
|
||||||
fetchMediaUseCase: FetchMediaUseCase
|
withPageContext<ImageGalleryPage.Folders> {
|
||||||
) = createReducer(
|
pageDispatch(PageStateChange.UpdatePage(it.copy(content = Lce.Content(folders))))
|
||||||
initialState = Unit,
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
async(ImageGalleryActions.Visible::class) {
|
async(ImageGalleryActions.SelectFolder::class) { action ->
|
||||||
jobBag.replace("page", coroutineScope.launch {
|
val page = SpiderPage(
|
||||||
val folders = foldersUseCase.fetchFolders()
|
route = ImageGalleryPage.Routes.files,
|
||||||
dispatch(PageAction.UpdatePage(ImageGalleryPage.Folders(Lce.Content(folders))))
|
label = rawPage().label,
|
||||||
})
|
parent = ImageGalleryPage.Routes.folders,
|
||||||
},
|
state = ImageGalleryPage.Files(Lce.Loading(), action.folder)
|
||||||
|
)
|
||||||
|
|
||||||
async(ImageGalleryActions.SelectFolder::class) { action ->
|
dispatch(PageAction.GoTo(page))
|
||||||
val page = SpiderPage(
|
|
||||||
route = ImageGalleryPage.Routes.files,
|
jobBag.replace(ImageGalleryPage.Files::class, coroutineScope.launch {
|
||||||
label = getSharedState().state1.page.label,
|
val media = fetchMediaUseCase.getMediaInBucket(action.folder.bucketId)
|
||||||
parent = ImageGalleryPage.Routes.folders,
|
withPageContext<ImageGalleryPage.Files> {
|
||||||
state = ImageGalleryPage.Files(Lce.Loading(), action.folder)
|
pageDispatch(PageStateChange.UpdatePage(it.copy(content = Lce.Content(media))))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
sideEffect(PageStateChange.ChangePage::class) { action, _ ->
|
||||||
|
jobBag.cancel(action.previous::class)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
dispatch(PageAction.GoTo(page))
|
|
||||||
|
|
||||||
jobBag.replace("page", coroutineScope.launch {
|
|
||||||
val media = fetchMediaUseCase.getMediaInBucket(action.folder.bucketId)
|
|
||||||
dispatch(PageAction.UpdatePage(page.state.copy(content = Lce.Content(media))))
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
sideEffect(PageAction.GoTo::class) { action, _ ->
|
|
||||||
if (getSharedState().state1.isDifferentPage(action.page)) {
|
|
||||||
jobBag.cancel("page")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,10 +5,7 @@ import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.State
|
import app.dapk.st.core.State
|
||||||
import app.dapk.st.core.ThemeStore
|
import app.dapk.st.core.ThemeStore
|
||||||
import app.dapk.st.core.page.PageAction
|
import app.dapk.st.core.page.*
|
||||||
import app.dapk.st.core.page.PageContainer
|
|
||||||
import app.dapk.st.core.page.createPageReducer
|
|
||||||
import app.dapk.st.core.page.withPageContext
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
import app.dapk.st.design.components.SpiderPage
|
||||||
import app.dapk.st.domain.StoreCleaner
|
import app.dapk.st.domain.StoreCleaner
|
||||||
import app.dapk.st.domain.application.eventlog.LoggingStore
|
import app.dapk.st.domain.application.eventlog.LoggingStore
|
||||||
|
@ -57,14 +54,14 @@ internal fun settingsReducer(
|
||||||
|
|
||||||
async(RootActions.FetchProviders::class) {
|
async(RootActions.FetchProviders::class) {
|
||||||
withPageContext<Page.PushProviders> {
|
withPageContext<Page.PushProviders> {
|
||||||
pageDispatch(PageAction.UpdatePage(it.copy(options = Lce.Loading())))
|
pageDispatch(PageStateChange.UpdatePage(it.copy(options = Lce.Loading())))
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentSelection = pushTokenRegistrars.currentSelection()
|
val currentSelection = pushTokenRegistrars.currentSelection()
|
||||||
val options = pushTokenRegistrars.options()
|
val options = pushTokenRegistrars.options()
|
||||||
withPageContext<Page.PushProviders> {
|
withPageContext<Page.PushProviders> {
|
||||||
pageDispatch(
|
pageDispatch(
|
||||||
PageAction.UpdatePage(
|
PageStateChange.UpdatePage(
|
||||||
it.copy(
|
it.copy(
|
||||||
selection = currentSelection,
|
selection = currentSelection,
|
||||||
options = Lce.Content(options)
|
options = Lce.Content(options)
|
||||||
|
@ -82,7 +79,7 @@ internal fun settingsReducer(
|
||||||
|
|
||||||
async(RootActions.ImportKeysFromFile::class) { action ->
|
async(RootActions.ImportKeysFromFile::class) { action ->
|
||||||
withPageContext<Page.ImportRoomKey> {
|
withPageContext<Page.ImportRoomKey> {
|
||||||
pageDispatch(PageAction.UpdatePage(it.copy(importProgress = ImportResult.Update(0))))
|
pageDispatch(PageStateChange.UpdatePage(it.copy(importProgress = ImportResult.Update(0))))
|
||||||
}
|
}
|
||||||
|
|
||||||
with(chatEngine) {
|
with(chatEngine) {
|
||||||
|
@ -92,7 +89,7 @@ internal fun settingsReducer(
|
||||||
fileStream.importRoomKeys(action.passphrase)
|
fileStream.importRoomKeys(action.passphrase)
|
||||||
.onEach { progress ->
|
.onEach { progress ->
|
||||||
withPageContext<Page.ImportRoomKey> {
|
withPageContext<Page.ImportRoomKey> {
|
||||||
pageDispatch(PageAction.UpdatePage(it.copy(importProgress = progress)))
|
pageDispatch(PageStateChange.UpdatePage(it.copy(importProgress = progress)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(coroutineScope)
|
.launchIn(coroutineScope)
|
||||||
|
@ -100,7 +97,7 @@ internal fun settingsReducer(
|
||||||
onFailure = {
|
onFailure = {
|
||||||
|
|
||||||
withPageContext<Page.ImportRoomKey> {
|
withPageContext<Page.ImportRoomKey> {
|
||||||
pageDispatch(PageAction.UpdatePage(it.copy(importProgress = ImportResult.Error(ImportResult.Error.Type.UnableToOpenFile))))
|
pageDispatch(PageStateChange.UpdatePage(it.copy(importProgress = ImportResult.Error(ImportResult.Error.Type.UnableToOpenFile))))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -114,7 +111,7 @@ internal fun settingsReducer(
|
||||||
)
|
)
|
||||||
|
|
||||||
withPageContext<Page.ImportRoomKey> {
|
withPageContext<Page.ImportRoomKey> {
|
||||||
pageDispatch(PageAction.UpdatePage(it.copy(selectedFile = namedFile)))
|
pageDispatch(PageStateChange.UpdatePage(it.copy(selectedFile = namedFile)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -181,5 +178,4 @@ internal fun settingsReducer(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
internal typealias SettingsState = State<Combined2<PageContainer<Page>, Unit>, SettingsEvent>
|
internal typealias SettingsState = State<Combined2<PageContainer<Page>, Unit>, SettingsEvent>
|
||||||
|
|
Loading…
Reference in New Issue