All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.com.eygraber.vice.ViceContainer.kt Maven / Gradle / Ivy

package com.eygraber.vice

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.launch

public interface ViceContainer
  where V : ViceView, C : ViceCompositor, E : ViceEffects {
  public val view: V
  public val intents: SharedFlow
  public val compositor: C
  public val effects: E

  @Composable
  public fun OnBackPressedHandler(enabled: Boolean, onBackPressed: () -> Unit)

  @Composable
  public fun Vice() {
    RunVice(
      view = view,
      intents = intents as MutableSharedFlow,
      compositor = compositor,
      effects = effects,
      onBackPressedHandler = { enabled, onBackPressed ->
        OnBackPressedHandler(enabled, onBackPressed)
      },
    )
  }
}

@Composable
private fun  RunVice(
  view: ViceView,
  intents: MutableSharedFlow,
  compositor: ViceCompositor,
  effects: ViceEffects,
  onBackPressedHandler: @Composable (Boolean, () -> Unit) -> Unit,
) {
  val scope = rememberCoroutineScope {
    Dispatchers.Main.immediate
  }

  onBackPressedHandler(compositor.internalIsBackHandlerEnabled()) {
    compositor.internalOnBackPressed { intent ->
      // this is synchronous because the dispatcher is Main.immediate
      scope.launch {
        compositor.internalOnIntent(intent)
      }

      intents.tryEmit(intent)
    }
  }

  ViceUdf(
    view,
    intents,
    compositor,
    effects,
    scope,
  )
}

@Suppress("NOTHING_TO_INLINE")
@Composable
private inline fun  ViceUdf(
  view: ViceView,
  intents: SharedFlow,
  compositor: ViceCompositor,
  effects: ViceEffects,
  scope: CoroutineScope,
) {
  effects.Launch()

  val state = compositor.internalComposite(intents)
  val intentHandler: (I) -> Unit = remember(scope, compositor, intents) {
    { intent: I ->
      // this is synchronous because the dispatcher is Main.immediate
      scope.launch {
        compositor.internalOnIntent(intent)
      }

      (intents as MutableSharedFlow).tryEmit(intent)
    }
  }

  view.Render(state, intentHandler)
}