Merge pull request #271 from ouchadam/tech/state-submodule
screen-state submodule
This commit is contained in:
commit
4d829ac84e
|
@ -17,6 +17,9 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
|
||||||
- uses: actions/setup-java@v3
|
- uses: actions/setup-java@v3
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
|
@ -14,6 +14,9 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
|
@ -16,6 +16,9 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
|
@ -16,6 +16,8 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -17,6 +17,8 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
- uses: actions/setup-java@v2
|
- uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: 'adopt'
|
distribution: 'adopt'
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "screen-state"]
|
||||||
|
path = screen-state
|
||||||
|
url = git@github.com:ouchadam/screen-state.git
|
|
@ -163,7 +163,6 @@ ext.firebase = { dependencies, name ->
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (launchTask.contains("codeCoverageReport".toLowerCase())) {
|
if (launchTask.contains("codeCoverageReport".toLowerCase())) {
|
||||||
apply from: 'tools/coverage.gradle'
|
apply from: 'tools/coverage.gradle'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
package app.dapk.st.design.components
|
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun <T : Any> Spider(currentPage: SpiderPage<T>, onNavigate: (SpiderPage<out T>?) -> Unit, graph: SpiderScope.() -> Unit) {
|
|
||||||
val pageCache = remember { mutableMapOf<Route<*>, SpiderPage<out T>>() }
|
|
||||||
pageCache[currentPage.route] = currentPage
|
|
||||||
|
|
||||||
val navigateAndPopStack = {
|
|
||||||
pageCache.remove(currentPage.route)
|
|
||||||
onNavigate(pageCache[currentPage.parent])
|
|
||||||
}
|
|
||||||
val itemScope = object : SpiderItemScope {
|
|
||||||
override fun goBack() {
|
|
||||||
navigateAndPopStack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val computedWeb = remember(true) {
|
|
||||||
mutableMapOf<Route<*>, @Composable (T) -> Unit>().also { computedWeb ->
|
|
||||||
val scope = object : SpiderScope {
|
|
||||||
override fun <T> item(route: Route<T>, content: @Composable SpiderItemScope.(T) -> Unit) {
|
|
||||||
computedWeb[route] = { content(itemScope, it as T) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
graph.invoke(scope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
if (currentPage.hasToolbar) {
|
|
||||||
Toolbar(
|
|
||||||
onNavigate = navigateAndPopStack,
|
|
||||||
title = currentPage.label
|
|
||||||
)
|
|
||||||
}
|
|
||||||
BackHandler(onBack = navigateAndPopStack)
|
|
||||||
computedWeb[currentPage.route]!!.invoke(currentPage.state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
interface SpiderScope {
|
|
||||||
fun <T> item(route: Route<T>, content: @Composable SpiderItemScope.(T) -> Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SpiderItemScope {
|
|
||||||
fun goBack()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class SpiderPage<T>(
|
|
||||||
val route: Route<T>,
|
|
||||||
val label: String,
|
|
||||||
val parent: Route<*>?,
|
|
||||||
val state: T,
|
|
||||||
val hasToolbar: Boolean = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
@JvmInline
|
|
||||||
value class Route<out S>(val value: String)
|
|
|
@ -5,5 +5,4 @@ dependencies {
|
||||||
implementation project(":features:navigator")
|
implementation project(":features:navigator")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
api project(":domains:android:core")
|
api project(":domains:android:core")
|
||||||
api project(":domains:state")
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,53 +21,3 @@ inline fun <reified VM : ViewModel> ComponentActivity.viewModel(
|
||||||
}
|
}
|
||||||
return ViewModelLazy(VM::class, { viewModelStore }, { factoryPromise })
|
return ViewModelLazy(VM::class, { viewModelStore }, { factoryPromise })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline fun <reified S, E> ComponentActivity.state(
|
|
||||||
noinline factory: () -> State<S, E>
|
|
||||||
): Lazy<State<S, E>> {
|
|
||||||
val factoryPromise = object : Factory {
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
|
||||||
return when(modelClass) {
|
|
||||||
StateViewModel::class.java -> factory() as T
|
|
||||||
else -> throw Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return KeyedViewModelLazy(
|
|
||||||
key = S::class.java.canonicalName!!,
|
|
||||||
StateViewModel::class,
|
|
||||||
{ viewModelStore },
|
|
||||||
{ factoryPromise }
|
|
||||||
) as Lazy<State<S, E>>
|
|
||||||
}
|
|
||||||
|
|
||||||
class KeyedViewModelLazy<VM : ViewModel> @JvmOverloads constructor(
|
|
||||||
private val key: String,
|
|
||||||
private val viewModelClass: KClass<VM>,
|
|
||||||
private val storeProducer: () -> ViewModelStore,
|
|
||||||
private val factoryProducer: () -> ViewModelProvider.Factory,
|
|
||||||
) : Lazy<VM> {
|
|
||||||
private var cached: VM? = null
|
|
||||||
|
|
||||||
override val value: VM
|
|
||||||
get() {
|
|
||||||
val viewModel = cached
|
|
||||||
return if (viewModel == null) {
|
|
||||||
val factory = factoryProducer()
|
|
||||||
val store = storeProducer()
|
|
||||||
ViewModelProvider(
|
|
||||||
store,
|
|
||||||
factory,
|
|
||||||
CreationExtras.Empty
|
|
||||||
).get(key, viewModelClass.java).also {
|
|
||||||
cached = it
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
viewModel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun isInitialized(): Boolean = cached != null
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
package app.dapk.st.core
|
|
||||||
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.lifecycle.ViewModel
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import app.dapk.state.Action
|
|
||||||
import app.dapk.state.ReducerFactory
|
|
||||||
import app.dapk.state.Store
|
|
||||||
import app.dapk.state.createStore
|
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
|
||||||
import kotlinx.coroutines.flow.SharedFlow
|
|
||||||
|
|
||||||
class StateViewModel<S, E>(
|
|
||||||
reducerFactory: ReducerFactory<S>,
|
|
||||||
eventSource: MutableSharedFlow<E>,
|
|
||||||
) : ViewModel(), State<S, E> {
|
|
||||||
|
|
||||||
private val store: Store<S> = createStore(reducerFactory, viewModelScope)
|
|
||||||
override val events: SharedFlow<E> = eventSource
|
|
||||||
override val current
|
|
||||||
get() = _state!!
|
|
||||||
private var _state: S by mutableStateOf(store.getState())
|
|
||||||
|
|
||||||
init {
|
|
||||||
_state = store.getState()
|
|
||||||
store.subscribe {
|
|
||||||
_state = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun dispatch(action: Action) {
|
|
||||||
store.dispatch(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> createStateViewModel(block: (suspend (E) -> Unit) -> ReducerFactory<S>): StateViewModel<S, E> {
|
|
||||||
val eventSource = MutableSharedFlow<E>(extraBufferCapacity = 1)
|
|
||||||
val reducer = block { eventSource.emit(it) }
|
|
||||||
return StateViewModel(reducer, eventSource)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface State<S, E> {
|
|
||||||
fun dispatch(action: Action)
|
|
||||||
val events: SharedFlow<E>
|
|
||||||
val current: S
|
|
||||||
}
|
|
|
@ -1,95 +0,0 @@
|
||||||
package app.dapk.st.core.page
|
|
||||||
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.state.*
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
sealed interface PageAction<out P> : Action {
|
|
||||||
data class GoTo<P : Any>(val page: SpiderPage<P>) : PageAction<P>
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface PageStateChange : Action {
|
|
||||||
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 PageContainer<P>(
|
|
||||||
val page: SpiderPage<out P>
|
|
||||||
)
|
|
||||||
|
|
||||||
interface PageReducerScope<P> {
|
|
||||||
fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit)
|
|
||||||
fun rawPage(): SpiderPage<out P>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PageDispatchScope<PC> {
|
|
||||||
fun ReducerScope<*>.pageDispatch(action: PageAction<PC>)
|
|
||||||
fun getPageState(): PC?
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <P : Any, S : Any> createPageReducer(
|
|
||||||
initialPage: SpiderPage<out P>,
|
|
||||||
factory: PageReducerScope<P>.() -> ReducerFactory<S>,
|
|
||||||
): ReducerFactory<Combined2<PageContainer<P>, S>> = shareState {
|
|
||||||
combineReducers(createPageReducer(initialPage), factory(pageReducerScope()))
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <P : Any, S : Any> SharedStateScope<Combined2<PageContainer<P>, S>>.pageReducerScope() = object : PageReducerScope<P> {
|
|
||||||
override fun <PC : Any> withPageContent(page: KClass<PC>, block: PageDispatchScope<PC>.() -> Unit) {
|
|
||||||
val currentPage = getSharedState().state1.page.state
|
|
||||||
if (currentPage::class == page) {
|
|
||||||
val pageDispatchScope = object : PageDispatchScope<PC> {
|
|
||||||
override fun ReducerScope<*>.pageDispatch(action: PageAction<PC>) {
|
|
||||||
val currentPageGuard = getSharedState().state1.page.state
|
|
||||||
if (currentPageGuard::class == page) {
|
|
||||||
dispatch(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getPageState() = getSharedState().state1.page.state as? PC
|
|
||||||
}
|
|
||||||
block(pageDispatchScope)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun rawPage() = getSharedState().state1.page
|
|
||||||
}
|
|
||||||
|
|
||||||
@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))
|
|
||||||
} else {
|
|
||||||
dispatch(PageStateChange.UpdatePage(action.page.state))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
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) } }
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
plugins {
|
|
||||||
id 'kotlin'
|
|
||||||
id 'java-test-fixtures'
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation Dependencies.mavenCentral.kotlinCoroutinesCore
|
|
||||||
|
|
||||||
testFixturesImplementation testFixtures(project(":core"))
|
|
||||||
testFixturesImplementation Dependencies.mavenCentral.kotlinCoroutinesCore
|
|
||||||
testFixturesImplementation Dependencies.mavenCentral.kluent
|
|
||||||
testFixturesImplementation Dependencies.mavenCentral.mockk
|
|
||||||
testFixturesImplementation Dependencies.mavenCentral.kotlinCoroutinesTest
|
|
||||||
}
|
|
|
@ -1,194 +0,0 @@
|
||||||
package app.dapk.state
|
|
||||||
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
fun <S> createStore(reducerFactory: ReducerFactory<S>, coroutineScope: CoroutineScope): Store<S> {
|
|
||||||
val subscribers = mutableListOf<(S) -> Unit>()
|
|
||||||
var state: S = reducerFactory.initialState()
|
|
||||||
return object : Store<S> {
|
|
||||||
private val scope = createScope(coroutineScope, this)
|
|
||||||
private val reducer = reducerFactory.create(scope)
|
|
||||||
|
|
||||||
override fun dispatch(action: Action) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
state = reducer.reduce(action).also { nextState ->
|
|
||||||
if (nextState != state) {
|
|
||||||
subscribers.forEach { it.invoke(nextState) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getState() = state
|
|
||||||
|
|
||||||
override fun subscribe(subscriber: (S) -> Unit) {
|
|
||||||
subscribers.add(subscriber)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReducerFactory<S> {
|
|
||||||
fun create(scope: ReducerScope<S>): Reducer<S>
|
|
||||||
fun initialState(): S
|
|
||||||
}
|
|
||||||
|
|
||||||
fun interface Reducer<S> {
|
|
||||||
fun reduce(action: Action): S
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <S> createScope(coroutineScope: CoroutineScope, store: Store<S>) = object : ReducerScope<S> {
|
|
||||||
override val coroutineScope = coroutineScope
|
|
||||||
override fun dispatch(action: Action) = store.dispatch(action)
|
|
||||||
override fun getState(): S = store.getState()
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Store<S> {
|
|
||||||
fun dispatch(action: Action)
|
|
||||||
fun getState(): S
|
|
||||||
fun subscribe(subscriber: (S) -> Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ReducerScope<S> {
|
|
||||||
val coroutineScope: CoroutineScope
|
|
||||||
fun dispatch(action: Action)
|
|
||||||
fun getState(): S
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface ActionHandler<S> {
|
|
||||||
val key: KClass<Action>
|
|
||||||
|
|
||||||
class Async<S>(override val key: KClass<Action>, val handler: suspend ReducerScope<S>.(Action) -> Unit) : ActionHandler<S>
|
|
||||||
class Sync<S>(override val key: KClass<Action>, val handler: (Action, S) -> S) : ActionHandler<S>
|
|
||||||
class Delegate<S>(override val key: KClass<Action>, val handler: ReducerScope<S>.(Action) -> ActionHandler<S>) : ActionHandler<S>
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Combined2<S1, S2>(val state1: S1, val state2: S2)
|
|
||||||
|
|
||||||
fun interface SharedStateScope<C> {
|
|
||||||
fun getSharedState(): C
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> shareState(block: SharedStateScope<S>.() -> ReducerFactory<S>): ReducerFactory<S> {
|
|
||||||
var internalScope: ReducerScope<S>? = null
|
|
||||||
val scope = SharedStateScope { internalScope!!.getState() }
|
|
||||||
val combinedFactory = block(scope)
|
|
||||||
return object : ReducerFactory<S> {
|
|
||||||
override fun create(scope: ReducerScope<S>) = combinedFactory.create(scope).also { internalScope = scope }
|
|
||||||
override fun initialState() = combinedFactory.initialState()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S1, S2> combineReducers(r1: ReducerFactory<S1>, r2: ReducerFactory<S2>): ReducerFactory<Combined2<S1, S2>> {
|
|
||||||
return object : ReducerFactory<Combined2<S1, S2>> {
|
|
||||||
override fun create(scope: ReducerScope<Combined2<S1, S2>>): Reducer<Combined2<S1, S2>> {
|
|
||||||
val r1Scope = createReducerScope(scope) { scope.getState().state1 }
|
|
||||||
val r2Scope = createReducerScope(scope) { scope.getState().state2 }
|
|
||||||
|
|
||||||
val r1Reducer = r1.create(r1Scope)
|
|
||||||
val r2Reducer = r2.create(r2Scope)
|
|
||||||
return Reducer {
|
|
||||||
Combined2(r1Reducer.reduce(it), r2Reducer.reduce(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initialState(): Combined2<S1, S2> = Combined2(r1.initialState(), r2.initialState())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <S> createReducerScope(scope: ReducerScope<*>, state: () -> S) = object : ReducerScope<S> {
|
|
||||||
override val coroutineScope: CoroutineScope = scope.coroutineScope
|
|
||||||
override fun dispatch(action: Action) = scope.dispatch(action)
|
|
||||||
override fun getState() = state.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S> createReducer(
|
|
||||||
initialState: S,
|
|
||||||
vararg reducers: (ReducerScope<S>) -> ActionHandler<S>,
|
|
||||||
): ReducerFactory<S> {
|
|
||||||
return object : ReducerFactory<S> {
|
|
||||||
override fun create(scope: ReducerScope<S>): Reducer<S> {
|
|
||||||
val reducersMap = reducers
|
|
||||||
.map { it.invoke(scope) }
|
|
||||||
.groupBy { it.key }
|
|
||||||
|
|
||||||
return Reducer { action ->
|
|
||||||
val result = reducersMap.keys
|
|
||||||
.filter { it.java.isAssignableFrom(action::class.java) }
|
|
||||||
.fold(scope.getState()) { acc, key ->
|
|
||||||
val actionHandlers = reducersMap[key]!!
|
|
||||||
actionHandlers.fold(acc) { acc, handler ->
|
|
||||||
when (handler) {
|
|
||||||
is ActionHandler.Async -> {
|
|
||||||
scope.coroutineScope.launch {
|
|
||||||
handler.handler.invoke(scope, action)
|
|
||||||
}
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
|
|
||||||
is ActionHandler.Sync -> handler.handler.invoke(action, acc)
|
|
||||||
is ActionHandler.Delegate -> when (val next = handler.handler.invoke(scope, action)) {
|
|
||||||
is ActionHandler.Async -> {
|
|
||||||
scope.coroutineScope.launch {
|
|
||||||
next.handler.invoke(scope, action)
|
|
||||||
}
|
|
||||||
acc
|
|
||||||
}
|
|
||||||
|
|
||||||
is ActionHandler.Sync -> next.handler.invoke(action, acc)
|
|
||||||
is ActionHandler.Delegate -> error("is not possible")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun initialState(): S = initialState
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <A : Action, S> sideEffect(klass: KClass<A>, block: suspend (A, S) -> Unit): (ReducerScope<S>) -> ActionHandler<S> {
|
|
||||||
return {
|
|
||||||
ActionHandler.Async(key = klass as KClass<Action>) { action -> block(action as A, getState()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <A : Action, S> change(klass: KClass<A>, block: (A, S) -> S): (ReducerScope<S>) -> ActionHandler<S> {
|
|
||||||
return {
|
|
||||||
ActionHandler.Sync(key = klass as KClass<Action>, block as (Action, S) -> S)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <A : Action, S> async(klass: KClass<A>, block: suspend ReducerScope<S>.(A) -> Unit): (ReducerScope<S>) -> ActionHandler<S> {
|
|
||||||
return {
|
|
||||||
ActionHandler.Async(key = klass as KClass<Action>, block as suspend ReducerScope<S>.(Action) -> Unit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <A : Action, S> multi(klass: KClass<A>, block: Multi<A, S>.(A) -> (ReducerScope<S>) -> ActionHandler<S>): (ReducerScope<S>) -> ActionHandler<S> {
|
|
||||||
val multiScope = object : Multi<A, S> {
|
|
||||||
override fun sideEffect(block: suspend (S) -> Unit): (ReducerScope<S>) -> ActionHandler<S> = sideEffect(klass) { _, state -> block(state) }
|
|
||||||
override fun change(block: (A, S) -> S): (ReducerScope<S>) -> ActionHandler<S> = change(klass, block)
|
|
||||||
override fun async(block: suspend ReducerScope<S>.(A) -> Unit): (ReducerScope<S>) -> ActionHandler<S> = async(klass, block)
|
|
||||||
override fun nothing() = sideEffect { }
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
ActionHandler.Delegate(key = klass as KClass<Action>) { action ->
|
|
||||||
block(multiScope, action as A).invoke(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Multi<A : Action, S> {
|
|
||||||
fun sideEffect(block: suspend (S) -> Unit): (ReducerScope<S>) -> ActionHandler<S>
|
|
||||||
fun nothing(): (ReducerScope<S>) -> ActionHandler<S>
|
|
||||||
fun change(block: (A, S) -> S): (ReducerScope<S>) -> ActionHandler<S>
|
|
||||||
fun async(block: suspend ReducerScope<S>.(A) -> Unit): (ReducerScope<S>) -> ActionHandler<S>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Action
|
|
|
@ -1,20 +0,0 @@
|
||||||
package fake
|
|
||||||
|
|
||||||
import org.amshove.kluent.internal.assertEquals
|
|
||||||
|
|
||||||
class FakeEventSource<E> : (E) -> Unit {
|
|
||||||
|
|
||||||
private val captures = mutableListOf<E>()
|
|
||||||
|
|
||||||
override fun invoke(event: E) {
|
|
||||||
captures.add(event)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertEvents(expected: List<E>) {
|
|
||||||
assertEquals(expected, captures)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNoEvents() {
|
|
||||||
assertEquals(emptyList(), captures)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
package test
|
|
||||||
|
|
||||||
import app.dapk.state.Action
|
|
||||||
import app.dapk.state.Reducer
|
|
||||||
import app.dapk.state.ReducerFactory
|
|
||||||
import app.dapk.state.ReducerScope
|
|
||||||
import fake.FakeEventSource
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.amshove.kluent.internal.assertEquals
|
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
|
||||||
|
|
||||||
interface ReducerTest<S, E> {
|
|
||||||
operator fun invoke(block: suspend ReducerTestScope<S, E>.() -> Unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> testReducer(block: ((E) -> Unit) -> ReducerFactory<S>): ReducerTest<S, E> {
|
|
||||||
val fakeEventSource = FakeEventSource<E>()
|
|
||||||
val reducerFactory = block(fakeEventSource)
|
|
||||||
return object : ReducerTest<S, E> {
|
|
||||||
override fun invoke(block: suspend ReducerTestScope<S, E>.() -> Unit) {
|
|
||||||
runReducerTest(reducerFactory, fakeEventSource, block)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> runReducerTest(reducerFactory: ReducerFactory<S>, fakeEventSource: FakeEventSource<E>, block: suspend ReducerTestScope<S, E>.() -> Unit) {
|
|
||||||
runTest {
|
|
||||||
val expectTestScope = ExpectTest(coroutineContext)
|
|
||||||
block(ReducerTestScope(reducerFactory, fakeEventSource, expectTestScope))
|
|
||||||
expectTestScope.verifyExpects()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReducerTestScope<S, E>(
|
|
||||||
private val reducerFactory: ReducerFactory<S>,
|
|
||||||
private val fakeEventSource: FakeEventSource<E>,
|
|
||||||
private val expectTestScope: ExpectTestScope
|
|
||||||
) : ExpectTestScope by expectTestScope, Reducer<S> {
|
|
||||||
|
|
||||||
private var invalidateCapturedState: Boolean = false
|
|
||||||
private val actionSideEffects = mutableMapOf<Action, () -> S>()
|
|
||||||
private var manualState: S? = null
|
|
||||||
private var capturedResult: S? = null
|
|
||||||
|
|
||||||
private val actionCaptures = mutableListOf<Action>()
|
|
||||||
private val reducerScope = object : ReducerScope<S> {
|
|
||||||
override val coroutineScope = CoroutineScope(UnconfinedTestDispatcher())
|
|
||||||
override fun dispatch(action: Action) {
|
|
||||||
actionCaptures.add(action)
|
|
||||||
|
|
||||||
if (actionSideEffects.containsKey(action)) {
|
|
||||||
setState(actionSideEffects.getValue(action).invoke(), invalidateCapturedState = true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getState() = manualState ?: reducerFactory.initialState()
|
|
||||||
}
|
|
||||||
private val reducer: Reducer<S> = reducerFactory.create(reducerScope)
|
|
||||||
|
|
||||||
override fun reduce(action: Action) = reducer.reduce(action).also {
|
|
||||||
capturedResult = if (invalidateCapturedState) manualState else it
|
|
||||||
}
|
|
||||||
|
|
||||||
fun actionSideEffect(action: Action, handler: () -> S) {
|
|
||||||
actionSideEffects[action] = handler
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setState(state: S, invalidateCapturedState: Boolean = false) {
|
|
||||||
manualState = state
|
|
||||||
this.invalidateCapturedState = invalidateCapturedState
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setState(block: (S) -> S) {
|
|
||||||
setState(block(reducerScope.getState()))
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertInitialState(expected: S) {
|
|
||||||
reducerFactory.initialState() shouldBeEqualTo expected
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertEvents(events: List<E>) {
|
|
||||||
fakeEventSource.assertEvents(events)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertOnlyStateChange(expected: S) {
|
|
||||||
assertStateChange(expected)
|
|
||||||
assertNoDispatches()
|
|
||||||
fakeEventSource.assertNoEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertOnlyStateChange(block: (S) -> S) {
|
|
||||||
val expected = block(reducerScope.getState())
|
|
||||||
assertStateChange(expected)
|
|
||||||
assertNoDispatches()
|
|
||||||
fakeEventSource.assertNoEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertStateChange(expected: S) {
|
|
||||||
capturedResult shouldBeEqualTo expected
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertDispatches(expected: List<Action>) {
|
|
||||||
assertEquals(expected, actionCaptures)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNoDispatches() {
|
|
||||||
assertEquals(emptyList(), actionCaptures)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNoStateChange() {
|
|
||||||
assertEquals(reducerScope.getState(), capturedResult)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNoEvents() {
|
|
||||||
fakeEventSource.assertNoEvents()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertOnlyDispatches(expected: List<Action>) {
|
|
||||||
assertDispatches(expected)
|
|
||||||
fakeEventSource.assertNoEvents()
|
|
||||||
assertNoStateChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertOnlyEvents(events: List<E>) {
|
|
||||||
fakeEventSource.assertEvents(events)
|
|
||||||
assertNoDispatches()
|
|
||||||
assertNoStateChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun assertNoChanges() {
|
|
||||||
assertNoStateChange()
|
|
||||||
assertNoEvents()
|
|
||||||
assertNoDispatches()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> ReducerTestScope<S, E>.assertOnlyDispatches(vararg action: Action) {
|
|
||||||
this.assertOnlyDispatches(action.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> ReducerTestScope<S, E>.assertDispatches(vararg action: Action) {
|
|
||||||
this.assertDispatches(action.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> ReducerTestScope<S, E>.assertEvents(vararg event: E) {
|
|
||||||
this.assertEvents(event.toList())
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <S, E> ReducerTestScope<S, E>.assertOnlyEvents(vararg event: E) {
|
|
||||||
this.assertOnlyEvents(event.toList())
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ applyAndroidComposeLibraryModule(project)
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":chat-engine")
|
implementation project(":chat-engine")
|
||||||
implementation project(":domains:android:compose-core")
|
implementation project(":domains:android:compose-core")
|
||||||
implementation project(":domains:state")
|
implementation 'screen-state:screen-android'
|
||||||
implementation project(":features:messenger")
|
implementation project(":features:messenger")
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
|
@ -11,9 +11,9 @@ dependencies {
|
||||||
|
|
||||||
kotlinTest(it)
|
kotlinTest(it)
|
||||||
|
|
||||||
|
testImplementation 'screen-state:state-test'
|
||||||
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
||||||
androidImportFixturesWorkaround(project, project(":core"))
|
androidImportFixturesWorkaround(project, project(":core"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:state"))
|
|
||||||
androidImportFixturesWorkaround(project, project(":domains:store"))
|
androidImportFixturesWorkaround(project, project(":domains:store"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
||||||
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
||||||
|
|
|
@ -2,7 +2,7 @@ package app.dapk.st.directory
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import app.dapk.st.core.ProvidableModule
|
import app.dapk.st.core.ProvidableModule
|
||||||
import app.dapk.st.core.createStateViewModel
|
import app.dapk.st.state.createStateViewModel
|
||||||
import app.dapk.st.core.JobBag
|
import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.directory.state.DirectoryState
|
import app.dapk.st.directory.state.DirectoryState
|
||||||
import app.dapk.st.directory.state.directoryReducer
|
import app.dapk.st.directory.state.directoryReducer
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package app.dapk.st.directory.state
|
package app.dapk.st.directory.state
|
||||||
|
|
||||||
import app.dapk.st.core.State
|
import app.dapk.st.state.State
|
||||||
import app.dapk.st.engine.DirectoryState
|
import app.dapk.st.engine.DirectoryState
|
||||||
|
|
||||||
typealias DirectoryState = State<DirectoryScreenState, DirectoryEvent>
|
typealias DirectoryState = State<DirectoryScreenState, DirectoryEvent>
|
||||||
|
|
|
@ -9,7 +9,7 @@ dependencies {
|
||||||
implementation project(":domains:android:compose-core")
|
implementation project(":domains:android:compose-core")
|
||||||
implementation project(":domains:android:viewmodel")
|
implementation project(":domains:android:viewmodel")
|
||||||
implementation project(':domains:store')
|
implementation project(':domains:store')
|
||||||
implementation project(':domains:state')
|
implementation 'screen-state:screen-android'
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
implementation Dependencies.mavenCentral.coil
|
implementation Dependencies.mavenCentral.coil
|
||||||
|
|
|
@ -13,11 +13,11 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import app.dapk.st.core.DapkActivity
|
import app.dapk.st.core.DapkActivity
|
||||||
import app.dapk.st.core.module
|
import app.dapk.st.core.module
|
||||||
import app.dapk.st.core.state
|
|
||||||
import app.dapk.st.core.viewModel
|
import app.dapk.st.core.viewModel
|
||||||
import app.dapk.st.directory.DirectoryModule
|
import app.dapk.st.directory.DirectoryModule
|
||||||
import app.dapk.st.login.LoginModule
|
import app.dapk.st.login.LoginModule
|
||||||
import app.dapk.st.profile.ProfileModule
|
import app.dapk.st.profile.ProfileModule
|
||||||
|
import app.dapk.st.state.state
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ dependencies {
|
||||||
implementation project(":domains:android:compose-core")
|
implementation project(":domains:android:compose-core")
|
||||||
implementation project(":domains:android:viewmodel")
|
implementation project(":domains:android:viewmodel")
|
||||||
implementation project(":domains:store")
|
implementation project(":domains:store")
|
||||||
implementation project(":domains:state")
|
implementation 'screen-state:screen-android'
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
implementation project(":features:navigator")
|
implementation project(":features:navigator")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
|
@ -14,10 +14,10 @@ dependencies {
|
||||||
|
|
||||||
kotlinTest(it)
|
kotlinTest(it)
|
||||||
|
|
||||||
|
testImplementation 'screen-state:state-test'
|
||||||
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
||||||
androidImportFixturesWorkaround(project, project(":core"))
|
androidImportFixturesWorkaround(project, project(":core"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:store"))
|
androidImportFixturesWorkaround(project, project(":domains:store"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:state"))
|
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:viewmodel"))
|
androidImportFixturesWorkaround(project, project(":domains:android:viewmodel"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
||||||
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
||||||
|
|
|
@ -10,15 +10,17 @@ import androidx.compose.material3.Surface
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import app.dapk.st.core.*
|
import app.dapk.st.core.AndroidUri
|
||||||
|
import app.dapk.st.core.DapkActivity
|
||||||
|
import app.dapk.st.core.MimeType
|
||||||
import app.dapk.st.core.extensions.unsafeLazy
|
import app.dapk.st.core.extensions.unsafeLazy
|
||||||
|
import app.dapk.st.core.module
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
import app.dapk.st.messenger.gallery.GetImageFromGallery
|
import app.dapk.st.messenger.gallery.GetImageFromGallery
|
||||||
import app.dapk.st.messenger.state.ComposerStateChange
|
import app.dapk.st.messenger.state.ComposerStateChange
|
||||||
import app.dapk.st.messenger.state.MessengerEvent
|
|
||||||
import app.dapk.st.messenger.state.MessengerScreenState
|
|
||||||
import app.dapk.st.messenger.state.MessengerState
|
import app.dapk.st.messenger.state.MessengerState
|
||||||
import app.dapk.st.navigator.MessageAttachment
|
import app.dapk.st.navigator.MessageAttachment
|
||||||
|
import app.dapk.st.state.state
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@ -27,7 +29,7 @@ val LocalImageRequestFactory = staticCompositionLocalOf<ImageRequest.Builder> {
|
||||||
class MessengerActivity : DapkActivity() {
|
class MessengerActivity : DapkActivity() {
|
||||||
|
|
||||||
private val module by unsafeLazy { module<MessengerModule>() }
|
private val module by unsafeLazy { module<MessengerModule>() }
|
||||||
private val state by state { module.messengerState(readPayload()) }
|
private val state: MessengerState by state { module.messengerState(readPayload()) }
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import android.content.Context
|
||||||
import app.dapk.st.core.DeviceMeta
|
import app.dapk.st.core.DeviceMeta
|
||||||
import app.dapk.st.core.JobBag
|
import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.core.ProvidableModule
|
import app.dapk.st.core.ProvidableModule
|
||||||
import app.dapk.st.core.createStateViewModel
|
import app.dapk.st.state.createStateViewModel
|
||||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||||
import app.dapk.st.engine.ChatEngine
|
import app.dapk.st.engine.ChatEngine
|
||||||
import app.dapk.st.matrix.common.RoomId
|
import app.dapk.st.matrix.common.RoomId
|
||||||
|
|
|
@ -15,16 +15,17 @@ import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import app.dapk.st.core.*
|
import app.dapk.st.core.*
|
||||||
import app.dapk.st.core.extensions.unsafeLazy
|
|
||||||
import app.dapk.st.design.components.GenericError
|
import app.dapk.st.design.components.GenericError
|
||||||
|
import app.dapk.st.messenger.gallery.state.ImageGalleryState
|
||||||
|
import app.dapk.st.state.state
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
class ImageGalleryActivity : DapkActivity() {
|
class ImageGalleryActivity : DapkActivity() {
|
||||||
|
|
||||||
private val module by unsafeLazy { module<ImageGalleryModule>() }
|
private val imageGalleryState: ImageGalleryState by state {
|
||||||
private val imageGalleryState by state {
|
|
||||||
val payload = intent.getParcelableExtra("key") as? ImageGalleryActivityPayload
|
val payload = intent.getParcelableExtra("key") as? ImageGalleryActivityPayload
|
||||||
|
val module = module<ImageGalleryModule>()
|
||||||
module.imageGalleryState(payload!!.roomName)
|
module.imageGalleryState(payload!!.roomName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import android.provider.MediaStore
|
||||||
import app.dapk.st.core.CoroutineDispatchers
|
import app.dapk.st.core.CoroutineDispatchers
|
||||||
import app.dapk.st.core.JobBag
|
import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.core.ProvidableModule
|
import app.dapk.st.core.ProvidableModule
|
||||||
import app.dapk.st.core.createStateViewModel
|
import app.dapk.st.state.createStateViewModel
|
||||||
import app.dapk.st.messenger.gallery.state.ImageGalleryState
|
import app.dapk.st.messenger.gallery.state.ImageGalleryState
|
||||||
import app.dapk.st.messenger.gallery.state.imageGalleryReducer
|
import app.dapk.st.messenger.gallery.state.imageGalleryReducer
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,14 @@ import androidx.compose.ui.unit.sp
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.LifecycleEffect
|
import app.dapk.st.core.LifecycleEffect
|
||||||
import app.dapk.st.core.components.CenteredLoading
|
import app.dapk.st.core.components.CenteredLoading
|
||||||
import app.dapk.st.core.page.PageAction
|
|
||||||
import app.dapk.st.design.components.GenericError
|
import app.dapk.st.design.components.GenericError
|
||||||
import app.dapk.st.design.components.Spider
|
import app.dapk.st.design.components.Spider
|
||||||
import app.dapk.st.design.components.SpiderPage
|
import app.dapk.st.design.components.Toolbar
|
||||||
import app.dapk.st.messenger.gallery.state.ImageGalleryActions
|
import app.dapk.st.messenger.gallery.state.ImageGalleryActions
|
||||||
import app.dapk.st.messenger.gallery.state.ImageGalleryPage
|
import app.dapk.st.messenger.gallery.state.ImageGalleryPage
|
||||||
import app.dapk.st.messenger.gallery.state.ImageGalleryState
|
import app.dapk.st.messenger.gallery.state.ImageGalleryState
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
import coil.compose.rememberAsyncImagePainter
|
import coil.compose.rememberAsyncImagePainter
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
|
|
||||||
|
@ -44,7 +45,7 @@ fun ImageGalleryScreen(state: ImageGalleryState, onTopLevelBack: () -> Unit, onI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spider(currentPage = state.current.state1.page, onNavigate = onNavigate) {
|
Spider(currentPage = state.current.state1.page, onNavigate = onNavigate, toolbar = { navigate, title -> Toolbar(navigate, title) }) {
|
||||||
item(ImageGalleryPage.Routes.folders) {
|
item(ImageGalleryPage.Routes.folders) {
|
||||||
ImageGalleryFolders(
|
ImageGalleryFolders(
|
||||||
it,
|
it,
|
||||||
|
|
|
@ -2,15 +2,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.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.FetchMediaFoldersUseCase
|
import app.dapk.st.messenger.gallery.FetchMediaFoldersUseCase
|
||||||
import app.dapk.st.messenger.gallery.FetchMediaUseCase
|
import app.dapk.st.messenger.gallery.FetchMediaUseCase
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
import app.dapk.state.async
|
import app.dapk.state.async
|
||||||
import app.dapk.state.createReducer
|
import app.dapk.state.createReducer
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
import app.dapk.state.page.PageStateChange
|
||||||
|
import app.dapk.state.page.createPageReducer
|
||||||
|
import app.dapk.state.page.withPageContext
|
||||||
import app.dapk.state.sideEffect
|
import app.dapk.state.sideEffect
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package app.dapk.st.messenger.gallery.state
|
package app.dapk.st.messenger.gallery.state
|
||||||
|
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.State
|
import app.dapk.st.state.State
|
||||||
import app.dapk.st.design.components.Route
|
|
||||||
import app.dapk.st.messenger.gallery.Folder
|
import app.dapk.st.messenger.gallery.Folder
|
||||||
import app.dapk.st.messenger.gallery.Media
|
import app.dapk.st.messenger.gallery.Media
|
||||||
import app.dapk.st.core.page.PageContainer
|
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.Combined2
|
||||||
|
import app.dapk.state.Route
|
||||||
|
import app.dapk.state.page.PageContainer
|
||||||
|
|
||||||
typealias ImageGalleryState = State<Combined2<PageContainer<ImageGalleryPage>, Unit>, Unit>
|
typealias ImageGalleryState = State<Combined2<PageContainer<ImageGalleryPage>, Unit>, Unit>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package app.dapk.st.messenger.state
|
package app.dapk.st.messenger.state
|
||||||
|
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.State
|
import app.dapk.st.state.State
|
||||||
import app.dapk.st.design.components.BubbleModel
|
import app.dapk.st.design.components.BubbleModel
|
||||||
import app.dapk.st.engine.MessengerPageState
|
import app.dapk.st.engine.MessengerPageState
|
||||||
import app.dapk.st.engine.RoomEvent
|
import app.dapk.st.engine.RoomEvent
|
||||||
|
|
|
@ -2,15 +2,15 @@ package app.dapk.st.messenger.gallery.state
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
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.PageContainer
|
|
||||||
import app.dapk.st.core.page.PageStateChange
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.st.messenger.gallery.FetchMediaFoldersUseCase
|
import app.dapk.st.messenger.gallery.FetchMediaFoldersUseCase
|
||||||
import app.dapk.st.messenger.gallery.FetchMediaUseCase
|
import app.dapk.st.messenger.gallery.FetchMediaUseCase
|
||||||
import app.dapk.st.messenger.gallery.Folder
|
import app.dapk.st.messenger.gallery.Folder
|
||||||
import app.dapk.st.messenger.gallery.Media
|
import app.dapk.st.messenger.gallery.Media
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.Combined2
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
import app.dapk.state.page.PageContainer
|
||||||
|
import app.dapk.state.page.PageStateChange
|
||||||
import fake.FakeJobBag
|
import fake.FakeJobBag
|
||||||
import fake.FakeUri
|
import fake.FakeUri
|
||||||
import io.mockk.coEvery
|
import io.mockk.coEvery
|
||||||
|
@ -18,7 +18,6 @@ import io.mockk.mockk
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import test.assertOnlyDispatches
|
import test.assertOnlyDispatches
|
||||||
import test.delegateReturn
|
import test.delegateReturn
|
||||||
import test.expect
|
|
||||||
import test.testReducer
|
import test.testReducer
|
||||||
|
|
||||||
private const val A_ROOM_NAME = "a room name"
|
private const val A_ROOM_NAME = "a room name"
|
||||||
|
|
|
@ -4,16 +4,16 @@ dependencies {
|
||||||
implementation project(":chat-engine")
|
implementation project(":chat-engine")
|
||||||
implementation project(":features:settings")
|
implementation project(":features:settings")
|
||||||
implementation project(':domains:store')
|
implementation project(':domains:store')
|
||||||
implementation project(':domains:state')
|
implementation 'screen-state:screen-android'
|
||||||
implementation project(":domains:android:compose-core")
|
implementation project(":domains:android:compose-core")
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
|
|
||||||
kotlinTest(it)
|
kotlinTest(it)
|
||||||
|
|
||||||
|
testImplementation 'screen-state:state-test'
|
||||||
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
||||||
androidImportFixturesWorkaround(project, project(":core"))
|
androidImportFixturesWorkaround(project, project(":core"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:state"))
|
|
||||||
androidImportFixturesWorkaround(project, project(":domains:store"))
|
androidImportFixturesWorkaround(project, project(":domains:store"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
||||||
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
||||||
|
|
|
@ -2,7 +2,7 @@ package app.dapk.st.profile
|
||||||
|
|
||||||
import app.dapk.st.core.JobBag
|
import app.dapk.st.core.JobBag
|
||||||
import app.dapk.st.core.ProvidableModule
|
import app.dapk.st.core.ProvidableModule
|
||||||
import app.dapk.st.core.createStateViewModel
|
import app.dapk.st.state.createStateViewModel
|
||||||
import app.dapk.st.core.extensions.ErrorTracker
|
import app.dapk.st.core.extensions.ErrorTracker
|
||||||
import app.dapk.st.engine.ChatEngine
|
import app.dapk.st.engine.ChatEngine
|
||||||
import app.dapk.st.profile.state.ProfileState
|
import app.dapk.st.profile.state.ProfileState
|
||||||
|
|
|
@ -20,7 +20,6 @@ import androidx.compose.ui.unit.dp
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.LifecycleEffect
|
import app.dapk.st.core.LifecycleEffect
|
||||||
import app.dapk.st.core.components.CenteredLoading
|
import app.dapk.st.core.components.CenteredLoading
|
||||||
import app.dapk.st.core.page.PageAction
|
|
||||||
import app.dapk.st.design.components.*
|
import app.dapk.st.design.components.*
|
||||||
import app.dapk.st.engine.RoomInvite
|
import app.dapk.st.engine.RoomInvite
|
||||||
import app.dapk.st.engine.RoomInvite.InviteMeta
|
import app.dapk.st.engine.RoomInvite.InviteMeta
|
||||||
|
@ -28,6 +27,8 @@ import app.dapk.st.profile.state.Page
|
||||||
import app.dapk.st.profile.state.ProfileAction
|
import app.dapk.st.profile.state.ProfileAction
|
||||||
import app.dapk.st.profile.state.ProfileState
|
import app.dapk.st.profile.state.ProfileState
|
||||||
import app.dapk.st.settings.SettingsActivity
|
import app.dapk.st.settings.SettingsActivity
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfileScreen(viewModel: ProfileState, onTopLevelBack: () -> Unit) {
|
fun ProfileScreen(viewModel: ProfileState, onTopLevelBack: () -> Unit) {
|
||||||
|
@ -47,7 +48,7 @@ fun ProfileScreen(viewModel: ProfileState, onTopLevelBack: () -> Unit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spider(currentPage = viewModel.current.state1.page, onNavigate = onNavigate) {
|
Spider(currentPage = viewModel.current.state1.page, onNavigate = onNavigate, toolbar = { navigate, title -> Toolbar(navigate, title) }) {
|
||||||
item(Page.Routes.profile) {
|
item(Page.Routes.profile) {
|
||||||
ProfilePage(context, viewModel, it)
|
ProfilePage(context, viewModel, it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,14 @@ package app.dapk.st.profile.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.extensions.ErrorTracker
|
import app.dapk.st.core.extensions.ErrorTracker
|
||||||
import app.dapk.st.core.page.PageAction
|
|
||||||
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.engine.ChatEngine
|
import app.dapk.st.engine.ChatEngine
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
import app.dapk.state.async
|
import app.dapk.state.async
|
||||||
import app.dapk.state.createReducer
|
import app.dapk.state.createReducer
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
import app.dapk.state.page.PageStateChange
|
||||||
|
import app.dapk.state.page.createPageReducer
|
||||||
|
import app.dapk.state.page.withPageContext
|
||||||
import app.dapk.state.sideEffect
|
import app.dapk.state.sideEffect
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package app.dapk.st.profile.state
|
package app.dapk.st.profile.state
|
||||||
|
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.core.State
|
import app.dapk.st.state.State
|
||||||
import app.dapk.st.core.page.PageContainer
|
|
||||||
import app.dapk.st.design.components.Route
|
|
||||||
import app.dapk.st.engine.Me
|
import app.dapk.st.engine.Me
|
||||||
import app.dapk.st.engine.RoomInvite
|
import app.dapk.st.engine.RoomInvite
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.Combined2
|
||||||
|
import app.dapk.state.Route
|
||||||
|
import app.dapk.state.page.PageContainer
|
||||||
|
|
||||||
typealias ProfileState = State<Combined2<PageContainer<Page>, Unit>, Unit>
|
typealias ProfileState = State<Combined2<PageContainer<Page>, Unit>, Unit>
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package app.dapk.st.profile.state
|
package app.dapk.st.profile.state
|
||||||
|
|
||||||
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.PageContainer
|
|
||||||
import app.dapk.st.core.page.PageStateChange
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.st.engine.Me
|
import app.dapk.st.engine.Me
|
||||||
import app.dapk.st.matrix.common.HomeServerUrl
|
import app.dapk.st.matrix.common.HomeServerUrl
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.Combined2
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
import app.dapk.state.page.PageContainer
|
||||||
|
import app.dapk.state.page.PageStateChange
|
||||||
import fake.FakeChatEngine
|
import fake.FakeChatEngine
|
||||||
import fake.FakeErrorTracker
|
import fake.FakeErrorTracker
|
||||||
import fake.FakeJobBag
|
import fake.FakeJobBag
|
||||||
|
|
|
@ -7,15 +7,16 @@ dependencies {
|
||||||
implementation project(':domains:android:push')
|
implementation project(':domains:android:push')
|
||||||
implementation project(":domains:android:compose-core")
|
implementation project(":domains:android:compose-core")
|
||||||
implementation project(":domains:android:viewmodel")
|
implementation project(":domains:android:viewmodel")
|
||||||
|
implementation 'screen-state:screen-android'
|
||||||
implementation project(":design-library")
|
implementation project(":design-library")
|
||||||
implementation project(":core")
|
implementation project(":core")
|
||||||
|
|
||||||
kotlinTest(it)
|
kotlinTest(it)
|
||||||
|
|
||||||
|
testImplementation 'screen-state:state-test'
|
||||||
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
androidImportFixturesWorkaround(project, project(":matrix:common"))
|
||||||
androidImportFixturesWorkaround(project, project(":core"))
|
androidImportFixturesWorkaround(project, project(":core"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:store"))
|
androidImportFixturesWorkaround(project, project(":domains:store"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:state"))
|
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:viewmodel"))
|
androidImportFixturesWorkaround(project, project(":domains:android:viewmodel"))
|
||||||
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
androidImportFixturesWorkaround(project, project(":domains:android:stub"))
|
||||||
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
androidImportFixturesWorkaround(project, project(":chat-engine"))
|
||||||
|
|
|
@ -4,11 +4,15 @@ import android.os.Bundle
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import app.dapk.st.core.*
|
import app.dapk.st.core.DapkActivity
|
||||||
|
import app.dapk.st.core.module
|
||||||
|
import app.dapk.st.core.resetModules
|
||||||
|
import app.dapk.st.settings.state.SettingsState
|
||||||
|
import app.dapk.st.state.state
|
||||||
|
|
||||||
class SettingsActivity : DapkActivity() {
|
class SettingsActivity : DapkActivity() {
|
||||||
|
|
||||||
private val settingsState by state { module<SettingsModule>().settingsState() }
|
private val settingsState: SettingsState by state { module<SettingsModule>().settingsState() }
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import app.dapk.st.push.PushModule
|
||||||
import app.dapk.st.settings.eventlogger.EventLoggerViewModel
|
import app.dapk.st.settings.eventlogger.EventLoggerViewModel
|
||||||
import app.dapk.st.settings.state.SettingsState
|
import app.dapk.st.settings.state.SettingsState
|
||||||
import app.dapk.st.settings.state.settingsReducer
|
import app.dapk.st.settings.state.settingsReducer
|
||||||
|
import app.dapk.st.state.createStateViewModel
|
||||||
|
|
||||||
class SettingsModule(
|
class SettingsModule(
|
||||||
private val chatEngine: ChatEngine,
|
private val chatEngine: ChatEngine,
|
||||||
|
|
|
@ -41,7 +41,6 @@ import app.dapk.st.core.components.CenteredLoading
|
||||||
import app.dapk.st.core.components.Header
|
import app.dapk.st.core.components.Header
|
||||||
import app.dapk.st.core.extensions.takeAs
|
import app.dapk.st.core.extensions.takeAs
|
||||||
import app.dapk.st.core.getActivity
|
import app.dapk.st.core.getActivity
|
||||||
import app.dapk.st.core.page.PageAction
|
|
||||||
import app.dapk.st.design.components.*
|
import app.dapk.st.design.components.*
|
||||||
import app.dapk.st.engine.ImportResult
|
import app.dapk.st.engine.ImportResult
|
||||||
import app.dapk.st.navigator.Navigator
|
import app.dapk.st.navigator.Navigator
|
||||||
|
@ -51,6 +50,8 @@ import app.dapk.st.settings.state.ComponentLifecycle
|
||||||
import app.dapk.st.settings.state.RootActions
|
import app.dapk.st.settings.state.RootActions
|
||||||
import app.dapk.st.settings.state.ScreenAction
|
import app.dapk.st.settings.state.ScreenAction
|
||||||
import app.dapk.st.settings.state.SettingsState
|
import app.dapk.st.settings.state.SettingsState
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
|
||||||
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -66,7 +67,7 @@ internal fun SettingsScreen(settingsState: SettingsState, onSignOut: () -> Unit,
|
||||||
else -> settingsState.dispatch(PageAction.GoTo(it))
|
else -> settingsState.dispatch(PageAction.GoTo(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spider(currentPage = settingsState.current.state1.page, onNavigate = onNavigate) {
|
Spider(currentPage = settingsState.current.state1.page, onNavigate = onNavigate, toolbar = { navigate, title -> Toolbar(navigate, title) }) {
|
||||||
item(Page.Routes.root) {
|
item(Page.Routes.root) {
|
||||||
RootSettings(
|
RootSettings(
|
||||||
it,
|
it,
|
||||||
|
|
|
@ -2,10 +2,10 @@ package app.dapk.st.settings
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import app.dapk.st.core.Lce
|
import app.dapk.st.core.Lce
|
||||||
import app.dapk.st.design.components.Route
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.st.engine.ImportResult
|
import app.dapk.st.engine.ImportResult
|
||||||
import app.dapk.st.push.Registrar
|
import app.dapk.st.push.Registrar
|
||||||
|
import app.dapk.state.Route
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
|
||||||
internal data class SettingsScreenState(
|
internal data class SettingsScreenState(
|
||||||
val page: SpiderPage<out Page>,
|
val page: SpiderPage<out Page>,
|
||||||
|
@ -26,9 +26,9 @@ internal sealed interface Page {
|
||||||
|
|
||||||
object Routes {
|
object Routes {
|
||||||
val root = Route<Root>("Settings")
|
val root = Route<Root>("Settings")
|
||||||
val encryption = Route<Page.Security>("Encryption")
|
val encryption = Route<Security>("Encryption")
|
||||||
val pushProviders = Route<Page.PushProviders>("PushProviders")
|
val pushProviders = Route<PushProviders>("PushProviders")
|
||||||
val importRoomKeys = Route<Page.ImportRoomKey>("ImportRoomKey")
|
val importRoomKeys = Route<ImportRoomKey>("ImportRoomKey")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,8 @@ package app.dapk.st.settings.state
|
||||||
import android.content.ContentResolver
|
import android.content.ContentResolver
|
||||||
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.State
|
import app.dapk.st.state.State
|
||||||
import app.dapk.st.core.ThemeStore
|
import app.dapk.st.core.ThemeStore
|
||||||
import app.dapk.st.core.page.*
|
|
||||||
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
|
||||||
import app.dapk.st.domain.application.message.MessageOptionsStore
|
import app.dapk.st.domain.application.message.MessageOptionsStore
|
||||||
|
@ -16,10 +14,8 @@ import app.dapk.st.push.PushTokenRegistrars
|
||||||
import app.dapk.st.settings.*
|
import app.dapk.st.settings.*
|
||||||
import app.dapk.st.settings.SettingItem.Id.*
|
import app.dapk.st.settings.SettingItem.Id.*
|
||||||
import app.dapk.st.settings.SettingsEvent.*
|
import app.dapk.st.settings.SettingsEvent.*
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.*
|
||||||
import app.dapk.state.async
|
import app.dapk.state.page.*
|
||||||
import app.dapk.state.createReducer
|
|
||||||
import app.dapk.state.multi
|
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package app.dapk.st.settings
|
package app.dapk.st.settings
|
||||||
|
|
||||||
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.PageContainer
|
|
||||||
import app.dapk.st.core.page.PageStateChange
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.st.engine.ImportResult
|
import app.dapk.st.engine.ImportResult
|
||||||
import app.dapk.st.push.Registrar
|
import app.dapk.st.push.Registrar
|
||||||
import app.dapk.st.settings.state.ComponentLifecycle
|
import app.dapk.st.settings.state.ComponentLifecycle
|
||||||
|
@ -12,6 +8,10 @@ import app.dapk.st.settings.state.RootActions
|
||||||
import app.dapk.st.settings.state.ScreenAction
|
import app.dapk.st.settings.state.ScreenAction
|
||||||
import app.dapk.st.settings.state.settingsReducer
|
import app.dapk.st.settings.state.settingsReducer
|
||||||
import app.dapk.state.Combined2
|
import app.dapk.state.Combined2
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
import app.dapk.state.page.PageAction
|
||||||
|
import app.dapk.state.page.PageContainer
|
||||||
|
import app.dapk.state.page.PageStateChange
|
||||||
import fake.*
|
import fake.*
|
||||||
import fixture.aRoomId
|
import fixture.aRoomId
|
||||||
import internalfake.FakeSettingsItemFactory
|
import internalfake.FakeSettingsItemFactory
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package internalfixture
|
package internalfixture
|
||||||
|
|
||||||
import app.dapk.st.design.components.SpiderPage
|
|
||||||
import app.dapk.st.settings.Page
|
import app.dapk.st.settings.Page
|
||||||
|
import app.dapk.state.SpiderPage
|
||||||
|
|
||||||
internal fun aImportRoomKeysPage(
|
internal fun aImportRoomKeysPage(
|
||||||
state: Page.ImportRoomKey = Page.ImportRoomKey()
|
state: Page.ImportRoomKey = Page.ImportRoomKey()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 4e92f14031cc8be907cba09b3bfc1d9dbd380072
|
|
@ -6,6 +6,9 @@ dependencyResolutionManagement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "SmallTalk"
|
rootProject.name = "SmallTalk"
|
||||||
|
|
||||||
|
includeBuild 'screen-state'
|
||||||
|
|
||||||
include ':app'
|
include ':app'
|
||||||
|
|
||||||
include ':design-library'
|
include ':design-library'
|
||||||
|
|
Loading…
Reference in New Issue