main

square/leakcanary

Last updated at: 29/12/2023 09:38

ScreenHost.kt

TLDR

This file defines the ScreenHost composable function, responsible for rendering a screen host that handles navigation between different screens in a compose app.

Methods

No methods found in the file.

Classes

No classes found in the file.

package org.leakcanary.screens

import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.with
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import org.leakcanary.screens.Destination.ClientAppAnalysesDestination
import org.leakcanary.screens.Destination.ClientAppAnalysisDestination
import org.leakcanary.screens.Destination.ClientAppsDestination
import org.leakcanary.screens.Destination.LeakDestination
import org.leakcanary.screens.Destination.LeaksDestination
import org.leakcanary.screens.Destination.TreeMapDestination

// TODO Handle intents
@OptIn(ExperimentalMaterial3Api::class, ExperimentalAnimationApi::class)
@Composable
fun ScreenHost(backStack: BackStackViewModel = viewModel()) {
  val currentScreenState by backStack.currentScreenState.collectAsState()

  val appBarTitle by backStack.appBarTitle.collectAsState()

  BackHandler(enabled = currentScreenState.canGoBack) {
    backStack.goBack()
  }
  Scaffold(
    topBar = {
      TopAppBar(
        title = {
          Text(text = appBarTitle)
        },
        navigationIcon = {
          if (currentScreenState.canGoBack) {
            IconButton(onClick = {
              backStack.goBack()
            }) {
              Icon(Icons.Filled.ArrowBack, contentDescription = "Go back")
            }
          }
        }
      )
    }
  ) { paddingValues ->
    AnimatedContent(
      targetState = currentScreenState,
      transitionSpec = {
        val directionFactor = if (targetState.forward) 1 else -1
        slideInHorizontally(
          initialOffsetX = { fullWidth ->
            directionFactor * fullWidth
          }
        ) with slideOutHorizontally(targetOffsetX = { fullWidth ->
          directionFactor * -fullWidth
        })
      },
      modifier = Modifier.padding(paddingValues)
    ) { targetState ->
      Box(
        modifier = Modifier.fillMaxWidth()) {
        when (targetState.destination) {
          is ClientAppAnalysesDestination -> ClientAppAnalysesScreen()
          is ClientAppAnalysisDestination -> ClientAppAnalysisScreen()
          ClientAppsDestination -> ClientAppsScreen()
          is LeakDestination -> LeakScreen()
          is TreeMapDestination -> TreeMapScreen()
          LeaksDestination -> TODO()
        }
      }
    }
  }
}