diff --git a/core/src/main/kotlin/app/dapk/st/core/JobBag.kt b/core/src/main/kotlin/app/dapk/st/core/JobBag.kt index 3d91bfc..1e22518 100644 --- a/core/src/main/kotlin/app/dapk/st/core/JobBag.kt +++ b/core/src/main/kotlin/app/dapk/st/core/JobBag.kt @@ -1,6 +1,7 @@ package app.dapk.st.core import kotlinx.coroutines.Job +import kotlin.reflect.KClass class JobBag { @@ -11,8 +12,17 @@ class JobBag { jobs[key] = job } + fun replace(key: KClass<*>, job: Job) { + jobs[key.java.canonicalName]?.cancel() + jobs[key.java.canonicalName] = job + } + fun cancel(key: String) { jobs.remove(key)?.cancel() } + fun cancel(key: KClass<*>) { + jobs.remove(key.java.canonicalName)?.cancel() + } + } \ No newline at end of file diff --git a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/page/PageReducer.kt b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/page/PageReducer.kt index f33464a..aa43a46 100644 --- a/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/page/PageReducer.kt +++ b/domains/android/compose-core/src/main/kotlin/app/dapk/st/core/page/PageReducer.kt @@ -4,32 +4,12 @@ import app.dapk.st.design.components.SpiderPage import app.dapk.state.* import kotlin.reflect.KClass -fun

createPageReducer( - initialPage: SpiderPage -): ReducerFactory> { - return createReducer( - initialState = PageContainer( - page = initialPage - ), - - change(PageAction.GoTo::class) { action, state -> - state.copy(page = action.page as SpiderPage

) - }, - - change(PageAction.UpdatePage::class) { action, state -> - val isSamePage = state.page.state::class == action.pageContent::class - if (isSamePage) { - val updatedPageContent = (state.page as SpiderPage).copy(state = action.pageContent) - state.copy(page = updatedPageContent as SpiderPage) - } else { - state - } - }, - ) +sealed interface PageAction : Action { + data class GoTo

(val page: SpiderPage

) : PageAction

} -sealed interface PageAction

: Action { - data class GoTo

(val page: SpiderPage

) : PageAction

+sealed interface PageStateChange : Action { + data class ChangePage

(val previous: SpiderPage, val newPage: SpiderPage) : PageAction

data class UpdatePage

(val pageContent: P) : PageAction

} @@ -37,26 +17,23 @@ data class PageContainer

( val page: SpiderPage ) -fun PageContainer<*>.isDifferentPage(page: SpiderPage<*>): Boolean { - return page::class != this.page::class -} - -interface PageReducerScope { +interface PageReducerScope

{ fun withPageContent(page: KClass, block: PageDispatchScope.() -> Unit) + fun rawPage(): SpiderPage } -interface PageDispatchScope

{ - fun ReducerScope<*>.pageDispatch(action: PageAction

) - fun getPageState(): P? +interface PageDispatchScope { + fun ReducerScope<*>.pageDispatch(action: PageAction) + fun getPageState(): PC? } fun

createPageReducer( initialPage: SpiderPage, - factory: PageReducerScope.() -> ReducerFactory, + factory: PageReducerScope

.() -> ReducerFactory, ): ReducerFactory, S>> = shareState { combineReducers( createPageReducer(initialPage), - factory(object : PageReducerScope { + factory(object : PageReducerScope

{ override fun withPageContent(page: KClass, block: PageDispatchScope.() -> Unit) { val currentPage = getSharedState().state1.page.state if (currentPage::class == page) { @@ -73,11 +50,45 @@ fun

createPageReducer( block(pageDispatchScope) } } + + override fun rawPage() = getSharedState().state1.page }) ) } -inline fun PageReducerScope.withPageContext(crossinline block: PageDispatchScope.(PC) -> Unit) { +@Suppress("UNCHECKED_CAST") +private fun

createPageReducer( + initialPage: SpiderPage +): ReducerFactory> { + 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) + }, + + change(PageStateChange.UpdatePage::class) { action, state -> + val isSamePage = state.page.state::class == action.pageContent::class + if (isSamePage) { + val updatedPageContent = (state.page as SpiderPage).copy(state = action.pageContent) + state.copy(page = updatedPageContent as SpiderPage) + } else { + state + } + }, + ) +} + +inline fun PageReducerScope<*>.withPageContext(crossinline block: PageDispatchScope.(PC) -> Unit) { withPageContent(PC::class) { getPageState()?.let { block(it) } } } diff --git a/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/state/ImageGalleryReducer.kt b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/state/ImageGalleryReducer.kt index 360467f..fd37f1b 100644 --- a/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/state/ImageGalleryReducer.kt +++ b/features/messenger/src/main/kotlin/app/dapk/st/messenger/gallery/state/ImageGalleryReducer.kt @@ -3,11 +3,15 @@ package app.dapk.st.messenger.gallery.state import app.dapk.st.core.JobBag import app.dapk.st.core.Lce import app.dapk.st.core.page.PageAction -import app.dapk.st.core.page.PageContainer -import app.dapk.st.core.page.isDifferentPage +import app.dapk.st.core.page.PageStateChange +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.messenger.gallery.* -import app.dapk.state.* +import app.dapk.st.messenger.gallery.FetchMediaFoldersUseCase +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 fun imageGalleryReducer( @@ -15,54 +19,47 @@ fun imageGalleryReducer( foldersUseCase: FetchMediaFoldersUseCase, fetchMediaUseCase: FetchMediaUseCase, jobBag: JobBag, -) = shareState { - combineReducers( - createPageReducer(roomName), - createImageGalleryPageReducer(jobBag, foldersUseCase, fetchMediaUseCase), - ) -} - -private fun createPageReducer(roomName: String): ReducerFactory> = app.dapk.st.core.page.createPageReducer( - initialPage = SpiderPage( +) = createPageReducer( + initialPage = SpiderPage( route = ImageGalleryPage.Routes.folders, label = "Send to $roomName", parent = null, state = ImageGalleryPage.Folders(Lce.Loading()) - ) -) + ), + factory = { + createReducer( + initialState = Unit, -private fun SharedStateScope, Unit>>.createImageGalleryPageReducer( - jobBag: JobBag, - foldersUseCase: FetchMediaFoldersUseCase, - fetchMediaUseCase: FetchMediaUseCase -) = createReducer( - initialState = Unit, + async(ImageGalleryActions.Visible::class) { + jobBag.replace(ImageGalleryPage.Folders::class, coroutineScope.launch { + val folders = foldersUseCase.fetchFolders() + withPageContext { + pageDispatch(PageStateChange.UpdatePage(it.copy(content = Lce.Content(folders)))) + } + }) + }, - async(ImageGalleryActions.Visible::class) { - jobBag.replace("page", coroutineScope.launch { - val folders = foldersUseCase.fetchFolders() - dispatch(PageAction.UpdatePage(ImageGalleryPage.Folders(Lce.Content(folders)))) - }) - }, + async(ImageGalleryActions.SelectFolder::class) { action -> + val page = SpiderPage( + route = ImageGalleryPage.Routes.files, + label = rawPage().label, + parent = ImageGalleryPage.Routes.folders, + state = ImageGalleryPage.Files(Lce.Loading(), action.folder) + ) - async(ImageGalleryActions.SelectFolder::class) { action -> - val page = SpiderPage( - route = ImageGalleryPage.Routes.files, - label = getSharedState().state1.page.label, - parent = ImageGalleryPage.Routes.folders, - state = ImageGalleryPage.Files(Lce.Loading(), action.folder) + dispatch(PageAction.GoTo(page)) + + jobBag.replace(ImageGalleryPage.Files::class, coroutineScope.launch { + val media = fetchMediaUseCase.getMediaInBucket(action.folder.bucketId) + withPageContext { + 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") - } } ) diff --git a/features/settings/src/main/kotlin/app/dapk/st/settings/state/SettingsReducer.kt b/features/settings/src/main/kotlin/app/dapk/st/settings/state/SettingsReducer.kt index 173aa5c..9ccc1b9 100644 --- a/features/settings/src/main/kotlin/app/dapk/st/settings/state/SettingsReducer.kt +++ b/features/settings/src/main/kotlin/app/dapk/st/settings/state/SettingsReducer.kt @@ -5,10 +5,7 @@ import app.dapk.st.core.JobBag import app.dapk.st.core.Lce import app.dapk.st.core.State import app.dapk.st.core.ThemeStore -import app.dapk.st.core.page.PageAction -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.core.page.* import app.dapk.st.design.components.SpiderPage import app.dapk.st.domain.StoreCleaner import app.dapk.st.domain.application.eventlog.LoggingStore @@ -57,14 +54,14 @@ internal fun settingsReducer( async(RootActions.FetchProviders::class) { withPageContext { - pageDispatch(PageAction.UpdatePage(it.copy(options = Lce.Loading()))) + pageDispatch(PageStateChange.UpdatePage(it.copy(options = Lce.Loading()))) } val currentSelection = pushTokenRegistrars.currentSelection() val options = pushTokenRegistrars.options() withPageContext { pageDispatch( - PageAction.UpdatePage( + PageStateChange.UpdatePage( it.copy( selection = currentSelection, options = Lce.Content(options) @@ -82,7 +79,7 @@ internal fun settingsReducer( async(RootActions.ImportKeysFromFile::class) { action -> withPageContext { - pageDispatch(PageAction.UpdatePage(it.copy(importProgress = ImportResult.Update(0)))) + pageDispatch(PageStateChange.UpdatePage(it.copy(importProgress = ImportResult.Update(0)))) } with(chatEngine) { @@ -92,7 +89,7 @@ internal fun settingsReducer( fileStream.importRoomKeys(action.passphrase) .onEach { progress -> withPageContext { - pageDispatch(PageAction.UpdatePage(it.copy(importProgress = progress))) + pageDispatch(PageStateChange.UpdatePage(it.copy(importProgress = progress))) } } .launchIn(coroutineScope) @@ -100,7 +97,7 @@ internal fun settingsReducer( onFailure = { withPageContext { - 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 { - 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, Unit>, SettingsEvent>